题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2120
带修改的莫队;
用结构体存下修改和询问,排好序保证时间后就全局移动修改即可;
参考了TJ:https://blog.csdn.net/SmallSXJ/article/details/69676746
vis 标记得好精妙啊!这样修改都不用分别改加入和删除了!
还要注意区间的扩展和收缩在循环上有微妙不同,一定不要写错;
所以带修莫队也很简洁嘛!
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int const maxn=1e4+5; int n,m,a[maxn],b[maxn],pos[maxn],res,ans[maxn],base,cnt,tot,num[maxn*100]; bool vis[maxn]; struct N{int bh,x,y;}ch[maxn]; struct T{int pre,l,r,id;}q[maxn]; bool cmp(T x,T y){return (pos[x.l]==pos[y.l])?x.r<y.r:pos[x.l]<pos[y.l];} void change(int p) { if(vis[p]) { num[a[p]]--; if(num[a[p]]==0)res--; } else { num[a[p]]++; if(num[a[p]]==1)res++; } vis[p]^=1; } void update(int p,int x)//a[p]=x { if(vis[p]) { change(p); a[p]=x; change(p); } else a[p]=x; } void work() { int nw=0,l=1,r=0;// for(int i=1;i<=m;i++) { // while(nw<=q[i].pre)update(ch[nw].bh,ch[nw].y),nw++; // while(nw>q[i].pre)update(ch[nw].bh,ch[nw].x),nw--; // while(l<q[i].l)change(l),l++; // while(l>q[i].l)change(l),l--; // while(r<q[i].r)change(r),r++; // while(r>q[i].r)change(r),r--; // ans[q[i].id]=res; for(int j=nw+1;j<=q[i].pre;j++) update(ch[j].bh,ch[j].y); for(int j=nw;j>q[i].pre;j--) update(ch[j].bh,ch[j].x); for(int j=r+1;j<=q[i].r;j++) change(j);//注意扩展和收缩的不同! for(int j=r;j>q[i].r;j--) change(j); for(int j=l-1;j>=q[i].l;j--) change(j); for(int j=l;j<q[i].l;j++) change(j); ans[q[i].id]=res; l=q[i].l,r=q[i].r,nw=q[i].pre; } } int main() { scanf("%d%d",&n,&m); base=sqrt(n); for(int i=1;i<=n;i++) { pos[i]=(i-1)/base+1; scanf("%d",&a[i]); b[i]=a[i]; } char cc[3]; for(int i=1,x,y;i<=m;i++) { cin>>cc; scanf("%d%d",&x,&y); if(cc[0]=='R') { ch[++tot].bh=x; ch[tot].x=b[x]; ch[tot].y=y; b[x]=y; } else q[++cnt].pre=tot,q[cnt].l=x,q[cnt].r=y,q[cnt].id=cnt; } sort(q+1,q+m+1,cmp); work(); for(int i=1;i<=cnt;i++)printf("%d ",ans[i]); return 0; }