[bzoj2120] [洛谷P1903] 数颜色

Description###

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

Input###

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

Output###

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

Sample Input###

6 5

1 2 3 4 5 5

Q 1 4

Q 2 6

R 1 2

Q 1 4

Q 2 6

Sample Output###

4

4

3

4

HINT###

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。


想法##

带修改莫队。
与普通莫队其实一个意思,就是多了一个tim表示在这个询问操作时已进行了几次修改。
进行一些修改操作使当前状态与这个询问时原本的状态相同。


代码##

注意细节!!!

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N = 10005;

int block;
int bl(int x) { return (x-1)/block+1; }

int cnt1,cnt2;
struct ask{
    int l,r,id,tim;
    bool operator < (const ask &b) const{
        return bl(l)<bl(b.l) || (bl(l)==bl(b.l) && r<b.r);     
    }
}q[N];
struct cg{
    int x,fr,to;       
}d[N];

int a[N],cnt[1000005];
int cur,L,R;
void add(int x){
    cnt[a[x]]++;
    if(cnt[a[x]]==1) cur++;
}
void del(int x){
    cnt[a[x]]--;
    if(cnt[a[x]]==0) cur--;     
}

void cg_add(int x){
    int id=d[x].x;
    if(L<=id && id<=R){ // 注意是id(即d[x].x)啊,并不是x
        del(id);
        a[id]=d[x].to;
        add(id);
    }
    else a[id]=d[x].to;
}
void cg_del(int x){
    int id=d[x].x;
    if(L<=id && id<=R){
        del(id);
        a[id]=d[x].fr;
        add(id);
    }
    else a[id]=d[x].fr;     
}

int n,m;
int ans[N];

int main()
{
    char opt[1];
    int x,y;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++){
        scanf("%s",opt);
        scanf("%d%d",&x,&y);
        if(opt[0]=='Q'){
            cnt1++;
            q[cnt1]=(ask){x,y,cnt1,cnt2}; 
        }
        else{
            cnt2++;
            d[cnt2]=(cg){x,a[x],y};
            a[x]=y;
        }
    }
    block=sqrt(n);
    sort(q+1,q+cnt1+1);
    
    int t=cnt2;
    L=R=1;
    cnt[a[1]]++; cur=1;
    for(int i=1;i<=cnt1;i++){
        while(R<q[i].r) add(++R);
        while(L>q[i].l) add(--L);
        while(R>q[i].r) del(R--);
        while(L<q[i].l) del(L++);
        while(t>q[i].tim) cg_del(t--); //注意顺序!!
        while(t<q[i].tim) cg_add(++t);
        ans[q[i].id]=cur;
    }
    for(int i=1;i<=cnt1;i++) printf("%d\n",ans[i]);
    
    return 0;    
}
posted @ 2018-02-27 22:42  秋千旁的蜂蝶~  阅读(118)  评论(0编辑  收藏  举报