P2184 貪婪大陸
題目背景
面對螞蟻們的瘋狂進攻,小FF的Tower defence宣告失敗……人類被螞蟻們逼到了Greed Island上的一個海灣。現在,小FF的後方是一望無際的大海, 前方是變異了的超級螞蟻。 小FF還有大好前程,他可不想命喪於此, 於是他派遣手下最後一批改造SCV布置地雷以阻擋螞蟻們的進攻。
題目描述
小FF最後一道防線是一條長度為N的戰壕, 小FF擁有無數多種地雷,而SCV每次可以在[ L , R ]區間埋放同一種不同於之前已經埋放的地雷。 由於情況已經十萬火急,小FF在某些時候可能會詢問你在[ L‘ , R‘] 區間內有多少種不同的地雷, 他希望你能盡快的給予答復。
對於30%的數據: 0<=n, m<=1000;
對於100%的數據: 0<=n, m<=10^5.
輸入輸出格式
輸入格式:第一行為兩個整數n和m; n表示防線長度, m表示SCV布雷次數及小FF詢問的次數總和。
接下來有m行, 每行三個整數Q,L , R; 若Q=1 則表示SCV在[ L , R ]這段區間布上一種地雷, 若Q=2則表示小FF詢問當前[ L , R ]區間總共有多少種地雷。
輸出格式:對於小FF的每次詢問,輸出一個答案(單獨一行),表示當前區間地雷總數。
輸入輸出樣例
輸入樣例#1:5 4 1 1 3 2 2 5 1 2 4 2 3 5輸出樣例#1:
1
2
Solution:
本題要求一段區間雷的個數,等價於求該區間與多少個前面修改過的區間相交。
那麽我們用兩個樹狀數組$s,c$,$s$維護節點$i$之前有多少個區間的左端點,$c$維護節點$i$之前有多少個區間的右端點。
則每次修改區間$[x,y]$時,將$s$從$[x,n]$每一位$+1$,將$c$從$[y,n]$每一位$+1$,套用差分的思想只需單點修改即可。查詢區間$[x,y]$時,答案$=$$y$之前的區間左端點個數$-x$之前的區間右端點個數,套用了類似前綴和的思想。
代碼:
1 #include<bits/stdc++.h> 2#define il inline 3 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) 4 using namespace std; 5 const int N=1e5+7; 6 int n,m,s[N],c[N]; 7 il int gi(){ 8 int a=0;char x=getchar(); 9 while(x<‘0‘||x>‘9‘)x=getchar(); 10 while(x>=‘0‘&&x<=‘9‘)a=(a<<3)+(a<<1)+x-48,x=getchar(); 11 return a; 12 } 13 il void update(int k,int x,int *c){while(k<=n){c[k]+=x;k+=k&-k;}} 14 il int query(int x,int *c){int su=0;while(x){su+=c[x];x-=x&-x;}return su;} 15 int main(){ 16 n=gi(),m=gi(); 17 int f,x,y; 18 For(i,1,m){ 19 f=gi(),x=gi(),y=gi(); 20 if(f==1){ 21 update(x,1,s); 22 update(y,1,c); 23 } 24 else printf("%d\n",query(y,s)-query(x-1,c)); 25 } 26 return 0; 27 }
P2184 貪婪大陸