線段樹入門詳解,洛谷P3372 模板 線段樹 1

2022-05-28 19:18:10 字數 3283 閱讀 9377

關於線段樹:

本隨筆參考例題

p3372 【模板】線段樹 1

所謂線段樹就是把一串陣列拆分成乙個乙個線段形成的一棵樹。

比如說像這樣的乙個陣列1,2,3,4,5:

1 ~ 5 

/           \  

1 ~ 3           4 ~ 5

/   \         /   \

1 ~ 2      345

/     \

1           2

如圖所示,

這就類似於線段樹。

線段樹之所以稱之為樹是因為他分解出來的樣子類似於樹,如上圖所示。

1. 初始化 

關於初始化個人認為沒什麼好講,由於線段樹需要建樹所以個人比較懶就用了#define

1

#define mid (l+r)/2

2#define left root*2 //眾所周知,乙個節點的左兒子下標就是當前節點的下標(root)*2

3#define right root*2+1 //乙個節點的右兒子下標就是當前節點的下標(root)*2+1

4const

long

long maxn=1000000;5

struct

trtree[maxn*2+1

];

9long

long a[maxn*2+1

]; //那個陣列

10long

long n,m; //n表示a陣列的數字個數,m表示操作次數

2. 建樹

關於建樹:

1

void build(long

long root,long

long l,long

long

r)  

8build(left,l,mid); //遍歷他的左兒子(下標為left)與右兒子(下標為right),並且縮小區間用類似二分的方法

9 build(right,mid+1

,r);

10 tree[root].sum=tree[left].sum+tree[right].sum; //當左右兒子都有值的時候就構造自己,然後返回構造自己的父親

11 }

具體就是將乙個大的區間(比如上面例子1~5)一直分解成子區間,直到葉子節點為止然後再往上構造整棵樹。

3. 懶標記,區間修改,區間查詢

什麼是懶標記呢?這一點要和區間修改和區間查詢一起講。

顧名思義為了偷懶而做的標記(逃~

為了節省時間我們可以在修改線段樹某個數字的時候現標記出那個要修改的數字,在區間查詢的時候再根據標記來修改。

那麼先講那個呢?先講

1.懶標記

1

void lazy(long

long

root)

9 }

接著講2.區間修改

1

void update(long

long root,long

long l,long

long r,long

long

num)  8

lazy(root); //修改兒子節點

9update(left,l,r,num);               //遍歷左右兒子

10update(right,l,r,num);

11 tree[root].sum=tree[left].sum+tree[right].sum; //當前節點的值賦值成左右兒子相加的和

12 }

那麼隨後講講

3.區間查詢(本題要查詢一段區間的和):

1

long

long search(long

long root,long

long l,long

long

r)//大功告成~~qwq

那麼完整**就是:

1 #include2

using

namespace

std;

3#define mid (l+r)/2

4#define left root*2

5#define right root*2+1

6const

long

long maxn=1000000;7

struct

trtree[maxn*2+1

];11

long

long a[maxn*2+1

];12

long

long

n,m;

13void build(long

long root,long

long l,long

long

r)20

build(left,l,mid);

21 build(right,mid+1

,r);

22 tree[root].sum=tree[left].sum+tree[right].sum;23}

24void lazy(long

long

root)32}

33void update(long

long root,long

long l,long

long r,long

long

num)

40lazy(root);

41update(left,l,r,num);

42update(right,l,r,num);

43 tree[root].sum=tree[left].sum+tree[right].sum;44}

45long

long search(long

long root,long

long l,long

long

r)54

intmain()

65else70}

71return0;

72 }

view code

線段樹結束,如果有多種方式修改不妨再加乙個懶標記qwq。(scanf()沒有cin好看)(逃~

希望可以幫助剛學或想學線段樹的童鞋們。

洛谷 P3372 線段樹 1

今天植樹節,來種一棵線段樹。傳送門如題,已知乙個數列,你需要進行下面兩種操作 1.將某區間每乙個數加上x 2.求出某區間每乙個數的和 輸入格式 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第 i 個數字表示數列第 i 項的初始值。接下來m行每...

洛谷P3372 線段樹模板

線段樹講的很詳細的部落格 鏈結 includeusing namespace std typedef long long ll const int maxn 100005 ll dat maxn 儲存資料 ll tree maxn 2 儲存線段樹的陣列常開成資料的4倍大小 ll add maxn 2...

線段樹1 洛谷P3372

如題,已知乙個數列,你需要進行下面兩種操作 1.將某區間每乙個數加上x 2.求出某區間每乙個數的和 輸入格式 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3或4個整數,表示乙個操作,具體如下...