1. 程式人生 > >[Codevs] 1081 線段樹練習 2 ----“分塊!”

[Codevs] 1081 線段樹練習 2 ----“分塊!”

inpu can 結構 相關 mas 每一個 好的 sqrt efi

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個位置的數是多少。

輸出描述 Output Description

對於每個詢問輸出一行一個答案

樣例輸入 Sample Input

3

1 2 3

2

1 2 3 2

2 3

樣例輸出 Sample Output

5

數據範圍及提示 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 ----“分塊!”