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;
}
posted @ 2017-05-11 19:43  forever97  阅读(218)  评论(0编辑  收藏  举报