可以考虑以下 P2709 的做法。
先用莫队取下出现在 \([l_i,r_i]\) 的位置的数,然后二分求得 \(ask(x)=x\) 的最大 \(x\) 就是答案。
注意 \(0\) 不能加入树状数组,于是先给所有数加 \(1\)。
块长取 \(n^{0.55}\) 最佳。
#include<bits/stdc++.h>
using namespace std;
const int N = 200010; int n, m, cnt[N], in[N], a[N];
#define W while
struct BIT {
int tr[N]; int lbt(int x) {return x & (-x);}
void add(int x, int k) {for(; x < N; x += lbt(x)) tr[x] += k;}
int query(int x) {int sum = 0; for(; x; x -= lbt(x)) sum += tr[x]; return sum;}
} B;
void add(int x) {if(!cnt[x]) B.add(x, 1); cnt[x]++;}
void del(int x) {if(cnt[x] == 1) B.add(x, -1); cnt[x]--;}
int ask() {
int l = 1, r = N - 1, ans = 0;
while(l <= r) {
// cout << l << ' ' << r << '\n';
int mid = l + r >> 1;
if(B.query(mid) == mid) ans = mid, l = mid + 1;
else r = mid - 1;
}
return ans;
}
struct Q {int l, r, id;} q[N]; int ans[N];
bool cmp(Q a, Q b) {return in[a.l] != in[b.l] ? a.l < b.l : a.r < b.r;}
int main() {
ios::sync_with_stdio(0); cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i], a[i]++; int len = pow(n, 0.55);
for(int i = 1; i <= n; i++) in[i] = (i + len - 1) / len; int l = 1, r = 0;
// for(int i = 1; i <= n; i++) cout << in[i] << ' '; cout << '\n';
for(int i = 0; i < m; i++) cin >> q[i].l >> q[i].r, q[i].id = i; sort(q, q + m, cmp);
for(int i = 0; i < m; i++) {
W(r < q[i].r) add(a[++r]); W(r > q[i].r) del(a[r--]);
W(l < q[i].l) del(a[l++]); W(l > q[i].l) add(a[--l]);
ans[q[i].id] = ask();
}
for(int i = 0; i < m; i++) cout << ans[i] << '\n';
return 0;
}
标签:cnt,int,mid,问题,++,add,ans,区间,mex
From: https://www.cnblogs.com/Stitch0711/p/17455598.html