您的位置:首页 > 其它

[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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息