【题解】数颜色--带修改莫队
题目描述
墨墨购买了一套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;
}