[Codevs] 1081 線段樹練習 2 ----“分塊!”
阿新 • • 發佈:2017-09-12
inpu can 結構 相關 mas 每一個 好的 sqrt efi
輸出描述 Output Description
1081 線段樹練習 2
時間限制: 1 s 空間限制: 128000 KB 題目等級 : 大師 Master 題目描述 Description給你N個數,有兩種操作
1:給區間[a,b]的所有數都增加X
2:詢問第i個數是什麽?
輸入描述 Input Description
第一行一個正整數n,接下來n行n個整數,再接下來一個正整數Q,表示操作的個數. 接下來Q行每行若幹個整數。如果第一個數是1,後接3個正整數a,b,X,表示在區間[a,b]內每個數增加X,如果是2,後面跟1個整數i, 表示詢問第i個位置的數是多少。
對於每個詢問輸出一行一個答案
樣例輸入 Sample Input3
1 2 3
2
1 2 3 2
2 3
樣例輸出 Sample Output5
數據範圍及提示 Data Size & Hint數據範圍
1<=n<=100000
1<=q<=100000
分析 Analysis
qwq闊別一年,終於能用分塊寫啦!
這段時間在網上翻了一些博客,也翻了藍書和ACM模版小紅書,發現分塊寫法風格實在是多樣
像ACM紅書(就清華大學出版社+俞勇主編那本ACMXXX《算法與實現》),裏面寫成了純鏈表
藍書寫的就比較接近我現在的習慣,但是也是難以模仿
現在的分塊類型總結如下:
A. 將數據完全存在各種塊中(就是紅書那種塊狀鏈表,一個節點保存一塊的信息)
B. 將數據存在線性數組中,分塊相關的附屬信息用另外一個結構存,線性數組中每一個元素有對應的塊編號
個人覺得B. 比較好寫(其實是因為B.寫對了)
個人覺得寫的比較好的分塊範例是在 1081線段樹練習2 的題解裏找到的,推薦!
顯然,分塊的風格還是挺多的
之前也聽學長說分塊很難寫(因為細節部分容易出錯)還難調(我是挺難調的= =)
不過還是推薦學一學
代碼 Code
1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #define maxn 1000000 5 using namespace std; 6 7 int size,arr[maxn],block[maxn],add[maxn],n,q,swi,a,b,c; 8 9 void modify(int a,int b,int c){ 10 a--,b--; 11 for(int i = a;i <= min(block[a]*size-1,b);i++) 12 arr[i] += c; 13 if(block[a] != block[b]){ 14 for(int i = (block[b]-1)*size;i <= b;i++) 15 arr[i] += c; 16 } 17 for(int i = block[a]+1;i < block[b];i++) 18 add[i] += c; 19 } 20 21 int main(){ 22 scanf("%d",&n); 23 size = (int)sqrt(n); 24 for(int i = 0;i < n;i++) scanf("%d",&arr[i]); 25 for(int i = 0;i < n;i++) block[i] = i/size+1; 26 // for(int i = 0;i < n;i++) printf("#%d: block->%d\n",i+1,block[i]); 27 scanf("%d",&q); 28 for(int i = 1;i <= q;i++){ 29 scanf("%d",&swi); 30 if(swi%2){ 31 scanf("%d%d%d",&a,&b,&c); 32 // for(int i = 1;i <= n;i++) printf("#%d: add->%d\n",i,add[block[i]]); 33 modify(a,b,c); 34 }else{ 35 scanf("%d",&a); 36 printf("%d\n",arr[a-1]+add[block[a-1]]); 37 } 38 } 39 40 // for(int i = 0;i < n;i++) printf("#%d: block[%d]\n",i,block[i]); 41 42 return 0; 43 }分塊!
[Codevs] 1081 線段樹練習 2 ----“分塊!”