線段樹 模板題

2021-08-28 17:24:27 字數 2531 閱讀 4843

problem description

已知乙個數列,你需要進行下面兩種操作:

1.將某區間每乙個數加上x

2.求出某區間每乙個數的和

input

第一行包含兩個整數n、m,分別表示該數列數字的個數和操作的總個數。

第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。

接下來m行每行包含3或4個整數,表示乙個操作,具體如下:

操作1: 格式:1 x y k 含義:將區間[x,y]內每個數加上k

操作2: 格式:2 x y 含義:輸出區間[x,y]內每個數的和

output

包含若干行整數,即為所有操作2的結果。

sample input

5 51 5 4 2 3

2 2 4

1 2 3 2

2 3 4

1 1 5 1

2 1 4

sample output118

20tip

時空限制:1000ms,128m

data constraint

對於30%的資料:n≤8,m≤10

對於70%的資料:n≤1000,m≤10000

對於100%的資料:n≤100000,m≤100000

剛剛看到本題,很顯然,我們可以先嘗試一下暴力,當然,如果分塊的話,我們也可以大大加快我們對本題的處理。

那麼我們就有非常簡單的暴力**。

#include #define ll long long 

using namespace std;

ll n,m;

ll a[1000001];

int main()

break;

} }}

觀察本題,很顯然我們需要建立一棵線段樹,其每個節點都儲存一段區間的和, 並且我們可能需要乙個布林函式來幫助我們快速修改一段區間的值。當然,如果題目只是乙個值乙個值修改的話,我們可以選擇樹狀陣列來更快地處理問題。

那麼,什麼是線段樹呢?

線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。

簡單來說,線段樹的建立,一般是將乙個陣列tree,每乙個編號i都算乙個節點,那麼我們就可以得到任意乙個線段樹的節點 tree[i],並且使用結構體的方式儲存。

這樣,我們的tree[i],就可以記錄下它儲存的區間和的左端點 left 和右端點 right,以及這段區間的和 sum。同時,線段樹之所以是線段樹,是因為它的祖先、兒子存在包含關係。

簡單來說,如果我已經有乙個節點tree[i],那麼我們通過它所儲存的區間的中點 mid=(left+right)/2 ,那麼我可以再為這個節點 tree[i] 記錄兩個值 leftson , rightson ,表示它的左兒子和右兒子,那麼,左右兒子分別繼承父親節點的一部分區間和,為了盡量降低複雜度,我們選擇左右兒子分別繼承父親節點的一半區間,所得到的左兒子 tree[leftson] ,它的區間左端點仍為 left , 右端點變成了mid 。所以右兒子 tree[rightson],它的區間左端點則為 mid+1 ,右端點則是 right 。由此我們明白,左右兒子所記錄的區間和就是父親節點記錄的區間和,那麼我們就可以通過這一點,進行乙個搜尋。

我們從根節點進行搜尋一段區間,判斷這段區間是繼承到了左兒子還是右兒子處,也可能是兩個兒子分別占有一部分,然後分別進行搜尋,就可以得到答案。

也正是因為每個節點記錄的是一段區間和,所以我們修改一段區間的數的大小時,我們只需乙個節點乙個節點處理就可以了,當然,為了節約時間,我們可以引入變數 change 來記錄這個節點的所有兒子和它是否需要修改,然後在我們遍歷到存在change 的點時,我們只需要增加該節點的和,並將change繼承給它的各個兒子,就可以了。

所以,我們有如下**。

#include #define ll long long  

using namespace std;

ll n,m;

ll q[100010];

struct nodev[270000];

void build(ll ,ll ,ll );

void change(ll ,ll ,ll ,ll );

ll find(ll ,ll ,ll );

int main()

else

printf("%lld\n",find(1,x,y));

}return 0;}

ll find(ll ro,ll le,ll ri)

void change(ll ro,ll le,ll ri,ll ca)

if (le>mid)

change(ro<<1,le,mid,ca);

change(ro<<1|1,mid+1,ri,ca);

return ;}

void build(ll ro,ll le,ll ri)

else

v[ro].sum=q[le];

return ;

}

線段樹(模板題)

對於一條數鏈,二分,然後二分,然後再二分 給定一數列,規定有兩種操作,一是修改某個元素,二是求區間的連續和。數列元素初始化為0 輸入 輸入資料第一行包含兩個正整數n,m n 100000,m 500000 以下是m行,每行有三個正整數k,a,b k 0或1,a,b n k 0時表示將a處數字加上b,...

線段樹之模板題

關於線段樹 首先應該是建樹 c國的死對頭a國這段時間正在進行軍事演習,所以c國間諜頭子derek和他手下tidy又開始忙乎了。a國在海岸線沿直線布置了n個工兵營地,derek和tidy的任務就是要監視這些工兵營地的活動情況。由於採取了某種先進的監測手段,所以每個工兵營地的人數c國都掌握的一清二楚,每...

線段樹 單點更新模板題

線段樹應該是資料結構中的一種吧,說白了,他就是一種工具,只要你學會了他,那麼你就可以在以後的學習中去用它。他的大致用法,就是把乙個一維陣列改變成乙個樹的結構,而且這個樹還是乙個完全二叉樹 上述圖就是把乙個1 8的區間變成了乙個二叉樹的結構,為什麼我們要這樣幹呢?這怎麼說呢?其實我也說不清楚。因為能力...