【bzoj2120: 數顏色】帶修改莫隊
阿新 • • 發佈:2019-01-31
2120: 數顏色
Time Limit: 6 Sec Memory Limit: 259 MBSubmit: 6501 Solved: 2593
[Submit][Status][Discuss]
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 51 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
Sample Output
44
3
4
HINT
對於100%的資料,N≤10000,M≤10000,修改操作不多於1000次,所有的輸入資料中出現的所有整數均大於等於1且不超過10^6。
剛開始忘了莫隊有個排序,,就直接暴力了,沒想到就過了,後來發現別人跑的比我的快很多,就想起來了。。。。
我們把修改操作和查詢操作分開來,莫隊一樣莫隊,我們在查詢的時候判斷這個查詢前面本來有多少個修改操作(一個查詢操作前的修改操作都是會影響當次查詢操作的),可以同莫隊類似的操作,如果還有沒操作的修改就修改,如果修改的多了就回撤回去。
由於我們有三個關鍵字,我們按照 l.block r.block time 這三個關鍵字順序排序,然後正常莫隊就好了。
為什麼要這樣排,我也不大清楚,據說這樣可以保證複雜度在O(n^(5/3))以內。這題資料水,暴力也沒壓力。
#include<cstdio> #include<cmath> #include<algorithm> #define N 1000005 using namespace std; int n,m,L,R,l,r,c[N],num[N],Num,cnt,cnt1,point; int ans[10005],sz,vis[10005]; char ch[2]; struct he{ int l,r,d,p,num,lst,l1,r1; }q[10005],q1[10005]; bool cmp(he a,he b){ if(a.l1==b.l1){ if(a.r1==b.r1) return a.num<b.num; return a.r1<b.r1; } return a.l1<b.l1; } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&c[i]); L=1;R=0; sz=sqrt(n)+1; for(int i=1;i<=m;i++){ scanf("%s%d%d",ch,&l,&r); if(ch[0]=='Q'){ cnt++; q[cnt].l=l;q[cnt].r=r;q[cnt].num=cnt1;q[cnt].p=cnt; q[cnt].l1=(l-1)/sz;q[cnt].r1=(r-1)/sz; } else { cnt1++; q1[cnt1].l=l;q1[cnt1].r=r; } } sort(q+1,q+1+cnt,cmp); point=0; for(int i=1;i<=cnt;i++){ int l=q[i].l,r=q[i].r; while(R<r) { R++; num[c[R]]++; if(num[c[R]]==1) Num++; } while(R>r){ num[c[R]]--; if(num[c[R]]==0) Num--; R--; } while(L>l){ L--; num[c[L]]++; if(num[c[L]]==1) Num++; } while(L<l){ num[c[L]]--; if(num[c[L]]==0) Num--; L++; } while(point<q[i].num){ point++; if(L<=q1[point].l&&q1[point].l<=R){ num[c[q1[point].l]]--; if(num[c[q1[point].l]]==0) Num--; num[q1[point].r]++; if(num[q1[point].r]==1) Num++; } q1[point].lst=c[q1[point].l]; c[q1[point].l]=q1[point].r; } while(point>q[i].num){ if(L<=q1[point].l&&q1[point].l<=R){ num[q1[point].r]--; if(num[q1[point].r]==0) Num--; num[q1[point].lst]++; if(num[q1[point].lst]==1) Num++; } c[q1[point].l]=q1[point].lst; point--; } ans[q[i].p]=Num; } for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]); }