[BZOJ3585&3339][Rmq Problem][莫队+二分+树状数组]
2017-03-29 18:58
513 查看
[BZOJ3585&3339][Rmq Problem][莫队+二分+树状数组]
题目大意:
有一个长度为n的数组{a1,a2,…,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。思路:
先把所有操作离线然后莫队,然后对于每个操作,先二分最多的从1开始一段连续的数n。(连续的一段值肯定是n)这样n+1就是最小没有出现过的自然数。然后把0特判一下就好了。有一个优化就是不考虑大于n的数,因为这些数肯定不会影响答案。
代码:
#include <bits/stdc++.h> using namespace std; const int Maxn = 200010; inline char get(void) { static char buf[100000], *p1 = buf, *p2 = buf; if (p1 == p2) { p2 = (p1 = buf) + fread(buf, 1, 100000, stdin); if (p1 == p2) return EOF; } return *p1++; } inline void read(int &x) { x = 0; static char c; for (; !(c >= '0' && c <= '9'); c = get()); for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); } int n, q, a[Maxn], bel[Maxn], ans[Maxn], t[Maxn], zero, block, c[Maxn]; inline int lowbit(int x) { return x & -x; } inline void add(int a, int v) { for (; a <= n; a += lowbit(a)) t[a] += v; } inline int query(int a) { int ret = 0; for (; a; a -= lowbit(a)) ret += t[a]; return ret; } inline void Add(int x, int v) { //cout << "Add " << x << ' ' << v << endl; if (x > n) return; if (!x) zero += v; else { int l = c[x]; c[x] += v; if (l == 0 && c[x] == 1) add(x, 1); if (l == 1 && c[x] == 0) add(x, -1); } } inline int Last(void) { if (!zero) return 0; int L = 0, R = n + 2, mid; while (L < R - 1) { mid = (L + R) >> 1; if (query(mid) == mid) L = mid; else R = mid; } return L + 1; } struct Cmd { int l, r, id; friend bool operator < (const Cmd &a, const Cmd &b) { if (bel[a.l] == bel[b.l]) return a.r < b.r; return a.l < b.l; } } cmd[Maxn]; inline void solve(void) { int L = 1, R = 0; for (int i = 1; i <= q; i++) { while (L < cmd[i].l) Add(a[L], -1), L++; while (L > cmd[i].l) L--, Add(a[L], 1); while (R > cmd[i].r) Add(a[R], -1), R--; while (R < cmd[i].r) R++, Add(a[R], 1); ans[cmd[i].id] = Last(); } } int main(void) { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); read(n), read(q); block = sqrt(n) + 1; for (int i = 1; i <= n; i++) { read(a[i]); bel[i] = (i - 1) / block + 1; } for (int i = 1; i <= q; i++) { read(cmd[i].l), read(cmd[i].r); cmd[i].id = i; } sort(cmd + 1, cmd + 1 + q); solve(); for (int i = 1; i <= q; i++) printf("%d\n", ans[i]); return 0; }
完。
By g1n0st
相关文章推荐
- Bzoj 3339: Rmq Problem && Bzoj 3585: mex 莫队,树状数组,二分
- BZOJ 3339: Rmq Problem 莫队算法
- Codeforces 387E George and Cards【思维+RMQ+二分+树状数组】被卡常= =
- BZOJ 3339: Rmq Problem|莫队算法
- BZOJ_3585_mex && BZOJ_3339_Rmq Problem_莫队+分块
- BZOJ 3339/3585 Rmq Problem/mex 莫队算法
- BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )
- hdu 5869 RMQ+二分+离线树状数组
- poj 3468 A Simple Problem with Integers 树状数组 或 线段树
- 【清澄A1333】【整体二分+二维树状数组】矩阵乘法(梁盾)
- BZOJ 2738: 矩阵乘法 整体二分 二维树状数组
- Codeforces Round #439 (Div. 2) Problem E (Codeforces 869E) - 暴力 - 随机化 - 二维树状数组 - 差分
- hdu4339之树状数组+二分
- ZOJ 3635 Cinema in Akiba(树状数组 + 二分)
- HDU4267 A Simple Problem with Integers(树状数组)
- HDU-4339 Query(树状数组+二分)
- ZOJ 4008 Yet Another Tree Query Problem [想法+树状数组]
- bzoj2738: 矩阵乘法【整体二分+二维树状数组】
- HDU 5493 Queue (树状数组+二分)2015 ICPC 合肥网赛
- [bzoj3289][树状数组][莫队算法]Mato的文件管理