题解原文地址:https://www.cnblogs.com/lujiaju6555/p/8468709.html
给数组a,有两种操作,1 l r查询[l,r]中每个数出现次数的mex,注意是出现次数,mex是最小未出现的自然数,2 x y将a[x]修改为y。
题解:带修改莫队可以解决此题。带修改莫队不会的同学可以先去做下BZOJ2120,然后mex+莫队可以参考BZOJ3585。带修改莫队就是加入了第三关键字time,然后按(左端点所在块,右端点所在块,时间)排序,其中时间指的是在第几次修改操作后。注意修改时要记下原来的数,以便还原回去。维护mex可以对权值分块,如果某块中数的个数==R-L+1,那么这块所有数都出现了,否则暴力扫,我有个同学直接暴力维护也过了。。。
#include <bits/stdc++.h> #define MOD 2018 #define LL long long #define ULL unsigned long long #define Pair pair<int, int> #define mem(a, b) memset(a, b, sizeof(a)) #define _ ios_base::sync_with_stdio(0),cin.tie(0) //freopen("1.txt", "r", stdin); using namespace std; const int maxn = 200005, INF = 0x7fffffff; int n, m, pos[maxn], s[maxn], c[maxn], all[maxn], t[maxn], cnt[maxn]; int qsz, csz; struct node { int l, r, t, res, id; }Node[maxn]; void add_n(int l, int r, int t, int id) { Node[id].l = l; Node[id].r = r; Node[id].t = t; Node[id].id = id; } struct change { int pos, New, Old; }Cha[maxn]; void add_c(int pos, int New, int Old, int ans) { Cha[ans].pos = pos; Cha[ans].New = New; Cha[ans].Old = Old; } bool cmp(node a, node b) { if(pos[a.l] == pos[b.l]) { if(pos[a.r] == pos[b.r]) return a.t < b.t; return pos[a.r] < pos[b.r]; } return pos[a.l] < pos[b.l]; } bool cmp_id(node a, node b) { return a.id < b.id; } int update(int val, int d) { if(s[val] > 0) cnt[s[val]]--; //s是记录val 出现的次数 cnt标记这个次数是否出现 因为有多个数 可能有些数出现的次数相同 所有用++即可 s[val] += d; //因为当前数val的次数改变 所以 如果未改变时的val的次数 给cnt贡献了1个的话 要先减去 再更新s[val] 再更新cnt[s[val]] if(s[val] > 0) cnt[s[val]]++; } int L=1, R=0, T=0; int go(int idx, int val) { if(L <= idx && idx <= R) //如果 当前时间内 修改的位置在当前区间 则先删去上一次在这个位置更新的值 再加上本次在这个位置更新的值 { update(c[idx], -1); update(val, 1); } c[idx] = val; //更新 } int main() { qsz = csz = 0; int tot = 0; scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) { scanf("%d",&c[i]); t[i] = c[i]; all[++tot] = c[i]; } int block=pow(n,2.0/3); for(int i=1; i<=n; i++) pos[i] = (i-1)/block + 1; for(int i=1; i<=m; i++) { int op, l, r; scanf("%d%d%d", &op, &l, &r); if(op == 1) { add_n(l, r, csz, ++qsz); } else { add_c(l, r, t[l], ++csz); t[l] = r; all[++tot] = r; } } sort(all+1, all+tot+1); tot = unique(all+1, all+tot+1) - (all + 1); for(int i=1; i<=n; i++) c[i] = lower_bound(all+1, all+tot+1, c[i]) - all; for(int i=1; i<=csz; i++) { Cha[i].New = lower_bound(all+1, all+tot+1, Cha[i].New) - all; Cha[i].Old = lower_bound(all+1, all+tot+1, Cha[i].Old) - all; } sort(Node+1, Node+qsz+1, cmp); for(int i=1; i<=qsz; i++) { // for(; T < Node[i].t; T++) // go(Cha[T+1].pos, Cha[T+1].New); // for(; T > Node[i].t; T--) // go(Cha[T].pos, Cha[T].Old); for(; R < Node[i].r; R++) update(c[R+1], 1); for(; R > Node[i].r; R--) update(c[R], -1); for(; L < Node[i].l; L++) update(c[L], -1); for(; L > Node[i].l; L--) update(c[L-1], 1); for(; T < Node[i].t; T++) //遍历在询问当前区间时 的 时间之前的修改 go(Cha[T+1].pos, Cha[T+1].New); for(; T > Node[i].t; T--) go(Cha[T].pos, Cha[T].Old); for(int j=1; ; j++) if(!cnt[j]) { Node[i].res = j; break; } // cout<< Node[i].res <<endl; } sort(Node+1, Node+qsz+1, cmp_id); for(int i=1; i<=qsz; i++) cout<< Node[i].res <<endl; return 0; }