本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!
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
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
4
3
4
HINT
對於100%的數據,N≤10000,M≤10000,修改操作不多於1000次,所有的輸入數據中出現的所有整數均大於等於1且不超過10^6。
正解:帶修改莫隊
解題報告:
這道題的數據范圍很小,以前寫過兩次,不過用的是暴力和分塊。
今天學可修改的莫隊,發現這是一道模板題就順便寫了。
因為莫隊是通過改變詢問的順序來降低整體復雜度,而帶修改的話就沒辦法處理先后順序的問題了。我們考慮加入修改操作之后如何保證算法復雜度。
因為查詢操作只有在查詢操作之前的所有修改操作完成之后才能保證正確性,也就是說我只要記錄了之前有多少個修改操作,然后在執行到當前查詢的時候我把多進行的修改操作還原,少進行的再進行修改就可以保證我的正確性。
同時為了保證復雜度,采取的策略是對於每個詢問按$(l/block,r/block,time)$排序(分別表示l所在的塊、r所在的詢問之前的修改次數),再順序完成,根據復雜度證明可以保證復雜度上界為$O(n^ {\frac{5}{3}} )$。
1 //It is made by ljh2000 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #include <string> 14 using namespace std; 15 typedef long long LL; 16 const int MAXN = 10011; 17 int n,m,a[MAXN],last[MAXN],cnt1,cnt2,block; 18 int L,R,head,ans,cnt[1000011],A[MAXN]; 19 char ch[12]; 20 struct ask{int l,r,lb,rb,tim,id;}q[MAXN]; 21 struct modify{int x,y,last;}r[MAXN]; 22 inline bool cmp(ask q,ask qq){ 23 if(q.lb==qq.lb) { 24 if(q.rb==qq.rb) return q.tim<qq.tim; 25 return q.rb<qq.rb; 26 } 27 return q.lb<qq.lb; 28 } 29 inline int getb(int x){ return (x-1)/block+1; } 30 inline int getint(){ 31 int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar(); 32 if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; 33 } 34 35 inline void change(int x,int col){ 36 if(L<=x&&x<=R) { 37 cnt[a[x]]--; if(cnt[a[x]]==0) ans--; 38 a[x]=col; 39 if(cnt[a[x]]==0) ans++; cnt[a[x]]++; 40 } 41 else a[x]=col; 42 } 43 44 inline void update(int x,int type){ 45 int cun=cnt[a[x]]; cnt[a[x]]+=type; 46 if(cun==0 && cnt[a[x]]==1) ans++; 47 else if(cun==1 && cnt[a[x]]==0) ans--; 48 } 49 50 inline void work(){ 51 n=getint(); m=getint(); for(int i=1;i<=n;i++) a[i]=getint(),last[i]=a[i]; 52 block=sqrt(n); 53 for(int i=1;i<=m;i++) { 54 scanf("%s",ch); 55 if(ch[0]=='R') { 56 r[++cnt1].x=getint(); 57 r[cnt1].y=getint(); 58 r[cnt1].last=last[r[cnt1].x]; 59 last[r[cnt1].x]=r[cnt1].y; 60 } 61 else{ 62 q[++cnt2].l=getint(); q[cnt2].r=getint(); q[cnt2].id=cnt2; 63 q[cnt2].lb=getb(q[cnt2].l); q[cnt2].rb=getb(q[cnt2].r); 64 q[cnt2].tim=cnt1; 65 } 66 } 67 sort(q+1,q+cnt2+1,cmp); L=1; R=0; head=0; 68 for(int i=1;i<=cnt2;i++) { 69 while(head>q[i].tim) { 70 change(r[head].x,r[head].last); 71 head--; 72 } 73 while(head<q[i].tim) { 74 head++; 75 change(r[head].x,r[head].y); 76 } 77 while(R<q[i].r) R++,update(R,1); 78 while(L>q[i].l) L--,update(L,1); 79 while(R>q[i].r) update(R,-1),R--; 80 while(L<q[i].l) update(L,-1),L++; 81 A[q[i].id]=ans; 82 } 83 for(int i=1;i<=cnt2;i++) printf("%d\n",A[i]); 84 } 85 86 int main() 87 { 88 work(); 89 return 0; 90 }