国家集训队——数颜色

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:

1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

2、 R P Col 把第P支画笔替换为颜色Col。

题解:

做这道题之前不会带修改莫队,山神学会了之后手(嘴)把手(嘴)教我打代码。

莫队算法先放下,带修改莫队是酱的:记下所有的修改,同时为每个询问加入一个时间标记,表示这个询问发生时修改到了哪一步。求解之前记录一个时间戳。每次求解一个询问时,先按普通莫队求解,然后查看当前时间戳和这个询问的标记,不一样的话就一个时间一个时间地改过去,同时修改答案。进行时间修改时,比如这道题,swap了修改的颜色和修改前的颜色,这样可以让之后发生时间倒流。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define MXN 10000+1
#define MXC 1000000+1
struct Query{int l,r,t,id;}q[MXN];
struct change{int p,co;}c[MXN];
int block[MXN];
bool cmp(Query A,Query B){
    if(block[A.l]==block[B.l]){
        if(A.r==B.r) return A.t<B.t;
        else return A.r<B.r;
    }
    else return block[A.l]<block[B.l];
}
int n,m,x,y;
int qsum,csum;
std::string p;
int color[MXN];
int man[MXC];
int ans[MXN];
void Change(int T,int i,int &temp){
    if(c[T].p>=q[i].l&&c[T].p<=q[i].r){
        man[color[c[T].p]]--;
        if(man[color[c[T].p]]==0) temp--;
        man[c[T].co]++;
        if(man[c[T].co]==1) temp++;
    }
    std::swap(color[c[T].p],c[T].co);
    return;
}
int main(){
    scanf("%d%d",&n,&m);
    int s=sqrt(n);
    for(int i=1;i<=n;i++){
        scanf("%d",&color[i]);
        block[i]=i/s;
    }
    while(m--){
        std::cin>>p;
        scanf("%d%d",&x,&y);
        if(p[0]=='Q'){
            q[qsum].l=x;
            q[qsum].r=y;
            q[qsum].id=qsum;
            q[qsum++].t=csum;
        }
        if(p[0]=='R'){
            c[++csum].p=x;
            c[csum].co=y;
        }
    }
    std::sort(q,q+qsum,cmp);
    int L=0,R=0,T=0,temp=0;
    for(int i=0;i<qsum;i++){
        while(L<q[i].l){man[color[L]]--;if(man[color[L]]==0) temp--;L++;}
        while(L>q[i].l){L--;man[color[L]]++;if(man[color[L]]==1) temp++;}
        while(R<q[i].r){R++;man[color[R]]++;if(man[color[R]]==1) temp++;}
        while(R>q[i].r){man[color[R]]--;if(man[color[R]]==0) temp--;R--;}
        while(T<q[i].t){T++;Change(T,i,temp);}
        while(T>q[i].t){Change(T,i,temp);T--;}
        ans[q[i].id]=temp;
    }
    for(int i=0;i<qsum;i++) printf("%d\n",ans[i]);
    return 0;
}
代码

PS:压行严重。

posted @ 2018-02-27 19:01  Halifuda  阅读(197)  评论(0编辑  收藏  举报