【题解】数颜色--带修改莫队

P1903-国家集训队-数颜色

题目描述

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

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

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

为了满足墨墨的要求,你知道你需要干什么了吗?

输入输出格式

输入格式:

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。

第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。

第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

输出格式:

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

输入输出样例

输入样例#1:

6 5

1 2 3 4 5 5

Q 1 4

Q 2 6

R 1 2

Q 1 4

Q 2 6

输出样例#1:

4

4

3

4

  • 说明

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

  • 来源:bzoj2120

    本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。

  • 分析

    题目目的很明确,用带修改的莫队,之前的莫队都是以l,r排序,这次我们再加一个作为第三个关键字t表示当前有几次修改发生来排序。

    推荐个大佬的博客:修改莫队

    具体还是看代码注释:

  • 代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cmath>
#define ri register int 
using namespace std;
const int maxn=10005;
int n,m,block;
int belong[maxn],last[maxn],a[maxn];
struct Ask{
    int l,r,id,t;
}ask[maxn];
struct Change
{
    int pos,c,pre;
}modify[maxn];
int cnt[1000010],ll=1,rr=0,q=0,cha=0,now=0;
int anss[maxn],ans=0;
inline bool cmp(const Ask & a,const Ask & b)
{
    if(belong[a.l]==belong[b.l])
    {
         if(belong[a.r]==belong[b.r])return a.t<b.t;
         return belong[a.r]<belong[b.r];
    }
    return belong[a.l]<belong[b.l];
}       //注意该排序的关键字
inline int read()
{
    int x,ne=0;char c;
    while(!isdigit(c=getchar()))ne=c=='-';
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    return ne?-x:x;
}//快读模板
inline void rewind(int u,int v)
{
    if(ll<=u&&u<=rr)//如果修改发生在当前区间要及时更新
    {
        cnt[a[u]]--;
        if(cnt[a[u]]==0)ans--;
        a[u]=v;
        cnt[v]++;
        if(cnt[v]==1)ans++;
    }
    else a[u]=v;
    return ;
}
inline void add(int now)
{
    cnt[now]++;
    if(cnt[now]==1)ans++;
    return ;
}
inline void sub(int now)
{
    cnt[now]--;
    if(cnt[now]==0)ans--;
    return ;
}
inline void solve()
{
    ll=1,rr=0,now=0,ans=0;
    for(ri i=1;i<=q;i++)
    {     //核心
        while(now>ask[i].t){                             rewind(modify[now].pos,modify[now].pre);
            now--;
        }
        while(now<ask[i].t){
            now++;                                       rewind(modify[now].pos,modify[now].c);
        }        
        while(rr<ask[i].r)add(a[++rr]);
        while(rr>ask[i].r)sub(a[rr]),rr--;
        while(ll<ask[i].l)sub(a[ll]),ll++;
        while(ll>ask[i].l)add(a[--ll]);
        anss[ask[i].id]=ans;
       // for(ri j=1;j<=n;j++)cout<<cnt[j]<<' ';
    }  
    for(ri i=1;i<=q;i++)
    {
        printf("%d\n",anss[i]);
    } 
}
int main()
{
    char op[10];
    n=read(),m=read(),block=sqrt(n);
    for(ri i=1;i<=n;i++){
        a[i]=read();last[i]=a[i];//注意这句话
        belong[i]=(i-1)/block+1;
    }
    for(ri i=1;i<=m;i++)
    {
        scanf("%s",op);
        if(op[0]=='Q'){
            ask[++q].l=read(),ask[q].r=read(),ask[q].id=q,ask[q].t=cha;
        }
        else{ 
 modify[++cha].pos=read(),modify[cha].c=read();
 modify[cha].pre=last[modify[cha].pos];                last[modify[cha].pos]=modify[cha].c;
        }
    }
    sort(ask+1,ask+1+q,cmp);
    solve();
    return 0;
}
posted @ 2018-02-27 14:41  Rye_Catcher  阅读(219)  评论(0编辑  收藏  举报