BZOJ 2120 数颜色(带修改莫队)
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2120
【题目大意】
给出一颜色序列,每次可以修改一个位置的颜色或者询问一个区间不同颜色的数目。
【题解】
我们按照最近一次修改对查询操作进行时间标号,在莫队排序的时候引入时间作为第三维,
对于每个修改操作,我们记录修改之前的颜色和修改之后的颜色,
对于两个相邻两个查询,我们将其之间时间差距的修改操作进行记录或者撤销之后查询即可。
【代码】
#include <cstdio> #include <algorithm> #include <cmath> const int N=1000010; using namespace std; int Ans,ans[N],pos[N],c[N],pre[N],sz,cnt,n,m,limit; struct Q{ int l,r,id,t; friend bool operator < (const Q &a,const Q &b){ if(pos[a.l]!=pos[b.l])return pos[a.l]<pos[b.l]; if(a.r!=b.r)return a.r<b.r; return a.t<b.t; } }ask[N]; struct update{int pos,c,pre;}w[N]; int in[N],num[N]; void cal(int x){ if(in[x]){if(!--num[c[x]])Ans--;} else{if(++num[c[x]]==1)Ans++;} in[x]^=1; } void update(int x,int y){ if(in[x]){cal(x);c[x]=y;cal(x);} else c[x]=y; } int main(){ while(~scanf("%d%d",&n,&m)){ int limit=sqrt(n); for(int i=1;i<=n;i++)scanf("%d",&c[i]),pre[i]=c[i],pos[i]=(i-1)/limit+1,in[i]=0; cnt=sz=Ans=0; for(int i=1;i<=m;i++){ char op[10]; scanf("%s",op); int x,y; scanf("%d%d",&x,&y); if(op[0]=='R'){w[++cnt].pos=x;w[cnt].c=y;w[cnt].pre=pre[x];pre[x]=y;} else{ask[++sz].l=x;ask[sz].r=y;ask[sz].id=sz;ask[sz].t=cnt;} }sort(ask+1,ask+sz+1); int l,r; cal(l=r=1); for(int i=1;i<=sz;i++){ for(int j=ask[i-1].t+1;j<=ask[i].t;j++)update(w[j].pos,w[j].c); for(int j=ask[i-1].t;j>ask[i].t;j--)update(w[j].pos,w[j].pre); while(l<ask[i].l)cal(l++); while(l>ask[i].l)cal(--l); while(r<ask[i].r)cal(++r); while(r>ask[i].r)cal(r--); ans[ask[i].id]=Ans; }for(int i=1;i<=sz;i++)printf("%d\n",ans[i]); }return 0; }
愿你出走半生,归来仍是少年