带修莫队
带修莫队,用于支持单点修改修改的区间查询,块长大小一般n的2/3次方理论最优,排序时先按l,再按r,最后按t升序排列
询问区间内不同颜色数,单点修改成另一颜色
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+6;
int n,m,a[N],bl[N],cnt[N],ans,qc,cc;
struct ask{
int l,r,t,id,ans;
inline bool friend operator<(const ask&a,const ask&b){
return bl[a.l]==bl[b.l]?bl[a.r]==bl[b.r]?a.t<b.t:a.r<b.r:a.l<b.l;
}
}q[N];
struct change{
int x,y;
}c[N];
inline void add(int x){
ans+=++cnt[x]==1;
}
inline void del(int x){
ans-=--cnt[x]==0;
}
inline void upd(int x,int t){
if(q[x].l<=c[t].x&&c[t].x<=q[x].r){/*如果修改的值在[l,r]之内,则其变化对答案有影响*/
del(a[c[t].x]);/*删除该位置上的值*/
add(c[t].y);/*添加新的值*/
}
swap(a[c[t].x],c[t].y);/*无论是否在查询区间内都要交换,使其变成原值或修改后的值*/
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
int len=pow(n,2.0/3.0);
for(int i=1;i<=n;i++)cin>>a[i],bl[i]=(i-1)/len+1;
for(int i=1;i<=m;i++){
char op[5];
int l,r;
cin>>op>>l>>r;
if(op[0]=='Q')q[++qc]={l,r,cc/*时间,在此之前有几个修改*/,qc/*编号,第几次查询*/};
else c[++cc]={l,r};
}
sort(q+1,q+1+qc);
for(int i=1,l=1,r=0,t=0;i<=qc;i++){
while(l>q[i].l)add(a[--l]);
while(r<q[i].r)add(a[++r]);
while(l<q[i].l)del(a[l++]);
while(r>q[i].r)del(a[r--]);
while(t<q[i].t)upd(i,++t);
while(t>q[i].t)upd(i,t--);
q[q[i].id].ans=ans;
}
for(int i=1;i<=qc;i++)cout<<q[i].ans<<'\n';
return 0;
}

浙公网安备 33010602011771号