1. 程式人生 > >貪婪大陸

貪婪大陸

人類 col 哪裏 con dig 數組 -s sample copy

題目背景

面對螞蟻們的瘋狂進攻,小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
坑點:一開始讀題沒有讀清楚,要求得是一段區間內有多少段不同的區間包括之前已有的地雷
也就是說不只是簡單的覆蓋問題。
導致我debug半天,還不知道是哪裏出了問題。
正解:
考慮用兩個樹狀數組維護。
對於加操作:
[L,R] add1(L,1) add2(R,1)
那麽相當於在第一個樹狀數組中對L->n打上了標記,但是R+1->n的標記是不應該
打上的,但是
在第二個樹狀數組中對R->n打上了標記,那麽第一和第二樹狀數組中R+1->n
的標記就可以看為相抵消了
在詢問的時候:[L,R]
ans=query1(R)-query2(L-1)
WU:真正做題的時候還是想不到正解,努力吧。
 1 #include<iostream>
 2
#include<cstdio> 3 #include<cmath> 4 #include<queue> 5 #define ll long long 6 #define inf 2147483600 7 #define DB double 8 using namespace std; 9 inline int read() 10 { 11 int x=0,w=1;char ch=getchar(); 12 while(!isdigit(ch)){if(ch==-) w=-1;ch=getchar();} 13 while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-0,ch=getchar(); 14 return x*w; 15 } 16 const int N=1e5+10; 17 int n,m; 18 int t1[N],t2[N]; 19 void add1(int x,int p) 20 { 21 while(x<=n) t1[x]+=p,x+=(x&(-x)); 22 } 23 int qq1(int x) 24 { 25 int ans=0; 26 while(x) ans+=t1[x],x-=(x&(-x)); 27 return ans; 28 } 29 void add2(int x,int p) 30 { 31 while(x<=n) t2[x]+=p,x+=(x&(-x)); 32 } 33 int qq2(int x) 34 { 35 int ans=0; 36 while(x) ans+=t2[x],x-=(x&(-x)); 37 return ans; 38 } 39 int main() 40 { 41 n=read();m=read(); 42 while(m--) 43 { 44 int op,L,R;op=read();L=read();R=read(); 45 if(L>R) swap(L,R); 46 if(op==1) add1(L,1),add2(R,1); 47 else cout<<qq1(R)-qq2(L-1)<<endl; 48 } 49 return 0; 50 }

沒有灑下汗水,怎麽收獲果實。






貪婪大陸