题目:
https://www.lydsy.com/JudgeOnline/problem.php?id=2120
分析:
在普通的莫队上,加上了修改操作,只需要在原来的基础上加一维时间,对于每一个询问记录下它是第几次修改后的询问,统计答案时,如果已经修改的序数 < 当前询问的修改序数,那么就将没有修改的执行修改操作,如果多修改了几次,则修改回去
这里要将1 - N 分成(N^(2/3))块,复杂度证明参考:戳戳戳~~
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4+14;
struct Segment{
int l,r,t,id;
}se[MAXN];
struct Revise{
int pos,col;
}re[MAXN];
int n,m,res,block,T,L,R,c[MAXN],vis[MAXN*100],ans[MAXN];
inline void revise(int T,int pos,int color){
if(L <= pos && pos <= R){
if(--vis[c[pos]] == 0) res--;
if(++vis[color] == 1) res++;
}
re[T].col = c[pos]; //方便修改回原来的颜色
c[pos] = color;
}
inline void add(int x){
if(!vis[c[x]]) res++;
vis[c[x]]++;
}
inline void del(int x){
if(vis[c[x]] == 1) res--;
vis[c[x]] --;
}
bool cmp(Segment a,Segment b){
return a.l/block==b.l/block?(a.r/block==b.r/block?a.t<b.t:a.r<b.r):a.l<b.l;
}
int main(){
cin >> n >> m;
block = pow(n,0.66666);
for(int i = 1;i <= n; ++i) cin >> c[i];
char op;
int qlen = 1,rlen = 0;
while(m--){
cin >> op;
if(op == 'Q'){
cin >> se[qlen].l >> se[qlen].r;
se[qlen].id = qlen;
se[qlen].t = rlen;
qlen++;
}
else{
++rlen;
cin >> re[rlen].pos >> re[rlen].col;
}
}
sort(se+1,se+qlen+1,cmp);
L = 1,R = 0,T = 0;
for(int i = 1;i <= qlen; ++i){
while(T < se[i].t) ++T,revise(T,re[T].pos,re[T].col);
while(T > se[i].t) revise(T,re[T].pos,re[T].col),--T;
while(L < se[i].l) del(L),++L;
while(L > se[i].l) --L,add(L);
while(R < se[i].r) ++R,add(R);
while(R > se[i].r) del(R),--R;
ans[se[i].id] = res;
}
for(int i = 1;i < qlen; ++i) cout << ans[i] << '\n';
return 0;
}