帶修改的莫隊
在學習了最基礎的莫隊後,我們會發現普通莫隊並不資瓷修改操作啊!!!這就很尷尬,那麽莫隊就沒辦法修改嗎,反正當時發明莫隊的人是沒有提到的,但是不要小瞧了智慧的OI人,不久就有人就提出了帶修改莫隊的想法。
如果你還沒不知道莫隊 點擊這裏!!!
其實剛知道莫隊還可以資瓷修改時,我以為代碼量會有質的飛越,但是學習後才發現原來不過如此,所以就別擔心了。。。
首先還是來一道題 數顏色
題目描述
墨墨購買了一套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≤50000,M≤50000,所有的輸入數據中出現的所有整數均大於等於1且不超過10^6。
本題可能輕微卡常數
來源:bzoj2120
【帶修改莫隊???】
向比較於普通的莫隊,我們多了修改操作,我們在普通莫隊時離線了詢問操作,所以這裏我們把修改也離線下來,並且在之前的左右指針基礎上,加一個時間戳,記錄我們當前到了哪個時間點了,同時我們維護每個詢問距離其最近的修改操作是什麽。
當我們處理到一個區間時,我們判斷當前時間點是否到了這個詢問最近的修改操作的時間點,如果不符合那麽我們就進行時間跳躍(是不是很秀的樣子)然後順便修改一下顏色,比起普通莫隊就多一個這個。。。當然帶了修改的莫隊復雜度會高一點,畢竟時間戳也要跳啊!!!
接下來我們來簡要地證明一下復雜度!(不是非常關心證明的同學,可以直接跳到結論部分……)
推移時間、移動左端點、移動右端點的操作都是O(1)的。
對於時間的移動,對於左右端點所在塊不變的情況,時間是單調向右移的,總共O(n); 左右端點之一所在塊改變,時間最多從n直接移回1,復雜度O(n);左右端點所在塊各有O(n^1/3)種,兩兩組合有O(n^2/3)種,每種都是O(n),總復雜度是O(n^5/3)。
對於右端點的移動,在左右端點所在塊不變時,每次最多移動n^2/3,一共最多有n次右端點的移動,復雜度是O(n^5/3);當左端點所在塊改變時,右端點最多從n一直移動到1,距離是n,最多有n^1/3次這樣的移動,復雜度是O(n^4/3);總共右端點移動的復雜度是O(n^5/3)。
對於左端點的移動,在左端點塊不變時,一次移動距離最多n23,總共O(n53)。而跨塊時,由於左端點所在塊是單調向右移動的,復雜度最大的情況就是每跨一個塊都是從前一個塊的最左側跑到後一個塊的最右側,距離O(n^1/3),總復雜度O(n)。所以總共左端點移動的復雜度是O(n^5/3)。
結論:上述排序方法實現的莫隊復雜度是O(n^5/3)。
具體實現讓我們在代碼中細細體會
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<iostream> 5 using namespace std; 6 inline int read() 7 { 8 char c=getchar();int x=0,f=1; 9 while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} 10 while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘,c=getchar();} 11 return x*f; 12 } 13 const int maxn=5e4+5; 14 const int M=1e6+5; 15 struct Qurey{ 16 int l,r,id,pre; 17 }que[maxn]; 18 struct Change{ 19 int pos,val; 20 }cc[maxn]; 21 int col[maxn],vis[M],be[maxn],res[maxn],n,m,qnum,cnum,ans; 22 bool cmp(Qurey a,Qurey b) 23 { 24 if(be[a.l]!=be[b.l]) return be[a.l]<be[b.l]; 25 if(be[a.r]!=be[b.r]) return be[a.r]<be[b.r]; 26 return a.pre<b.pre; 27 } 28 void change(int v,int add) 29 { 30 if(add==-1) if(--vis[col[v]]==0) ans--; 31 if(add==1) if(++vis[col[v]]==1) ans++; 32 } 33 void movetime(int time,int v) 34 { 35 if(que[v].l<=cc[time].pos&&que[v].r>=cc[time].pos) 36 { 37 if(++vis[cc[time].val]==1) ans++; 38 if(--vis[col[cc[time].pos]]==0) ans--; 39 } 40 swap(cc[time].val,col[cc[time].pos]); 41 } 42 void moque() 43 { 44 int l=1,r=0,time=0; 45 for(int i=1;i<=qnum;i++) 46 { 47 while(l<que[i].l) change(l++,-1); 48 while(l>que[i].l) change(--l,1); 49 while(r<que[i].r) change(++r,1); 50 while(r>que[i].r) change(r--,-1); 51 while(time<que[i].pre) movetime(++time,i); 52 while(time>que[i].pre) movetime(time--,i); 53 res[que[i].id]=ans; 54 } 55 for(int i=1;i<=qnum;i++) printf("%d\n",res[i]); 56 } 57 int main() 58 { 59 n=read(),m=read(); 60 int k=pow(n,2.0/3); 61 for(int i=1;i<=n;i++) 62 col[i]=read(),be[i]=(i-1)/k+1; 63 for(int i=1;i<=m;i++) 64 { 65 char ord[5]; 66 int a,b; 67 scanf("%s",ord); 68 a=read(),b=read(); 69 if(ord[0]==‘Q‘) 70 que[++qnum].id=qnum,que[qnum].l=a,que[qnum].r=b,que[qnum].pre=cnum; 71 if(ord[0]==‘R‘) 72 cc[++cnum].pos=a,cc[cnum].val=b; 73 } 74 sort(que+1,que+1+qnum,cmp); 75 moque(); 76 return 0; 77 }
帶修改的莫隊