題目描述
墨墨購買了一套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\n",ans[i]);
return 0;
}