题目描述
墨墨购买了一套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支画笔中共有几种不同颜色的画笔。
对于100%的数据,N≤50000,M≤50000,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
先不考虑修改颜色的操作,这个题就是个莫队的板子题。
然而这题还带修改。带修改的莫队怎么做呢?于是我赶紧去补习了一波。
对于当前询问,可以知道的是只有它之前的修改操作能够对它造成影响。所以我们可以记录下每个询问的前面有几次修改:
struct query{
int l,r,col,pre,id;
}q[maxm];
struct change{
int pos,val;
}c[maxm];
//main函数中
for(register int i=1;i<=m;i++){
cin>>op,l=read(),r=read();
if(op=='Q'){
q[++pos_q].l=l,q[pos_q].r=r,q[pos_q].col=l/unit+1;
q[pos_q].pre=pos_c,q[pos_q].id=pos_q;
}else c[++pos_c].pos=l,c[pos_c].val=r;
}
然后我们在莫队的时候加入一个计数的变量:now记录目前做了多少次修改。然后对于当前的第i个询问,设在这个询问之前一共有pre个修改操作,那么会有三种情况:
1.now<pre。那么把now+1~pre的修改加上去即可。
2.now=pre,不需要做任何操作。
3.now>pre。那么把pre+1~now的修改删去即可。
时间复杂度为O(N^(2/3)),但我并不知道怎么来的
O3瞩目
#pragma GCC optimize(3)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define maxn 50001
#define maxm 50001
#define maxcol 1000001
using namespace std;
int n,m,col[maxn];
inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
struct query{
int l,r,col,pre,id;
}q[maxm];
inline bool cmp(const query &a,const query &b){ return (a.col^b.col)?a.col<b.col:((a.col&1)?a.r>b.r:a.r<b.r); }
struct change{
int pos,val;
}c[maxm];
int pos_q,pos_c,unit;
int tot,cnt[maxcol],ans[maxn];
inline void add(const int &x){ tot+=(++cnt[col[x]]==1); }
inline void del(const int &x){ tot-=(--cnt[col[x]]==0); }
inline void Change(const int &now,const int &i){
if(q[i].l<=c[now].pos&&c[now].pos<=q[i].r){
tot-=(--cnt[col[c[now].pos]]==0);
tot+=(++cnt[c[now].val]==1);
}
swap(c[now].val,col[c[now].pos]);//用swap就可以把添加和删除询问压在一起
}
inline void MoQueue(){
sort(q+1,q+1+pos_q,cmp);
int l=1,r=0,now=0;
for(register int i=1;i<=pos_q;i++){
while(l<q[i].l) del(l++);
while(l>q[i].l) add(--l);
while(r<q[i].r) add(++r);
while(r>q[i].r) del(r--);
while(now<q[i].pre) Change(++now,i);
while(now>q[i].pre) Change(now--,i);
ans[q[i].id]=tot;
}
}
int main(){
n=read(),m=read(),unit=sqrt(n);
for(register int i=1;i<=n;i++) col[i]=read();
char op; int l,r;
for(register int i=1;i<=m;i++){
cin>>op,l=read(),r=read();
if(op=='Q'){
q[++pos_q].l=l,q[pos_q].r=r,q[pos_q].col=l/unit+1;
q[pos_q].pre=pos_c,q[pos_q].id=pos_q;
}else c[++pos_c].pos=l,c[pos_c].val=r;
}
MoQueue();
for(register int i=1;i<=pos_q;i++) printf("%d
",ans[i]);
return 0;
}