線段樹的實現鴨

2021-09-24 07:06:33 字數 2493 閱讀 4447

//線段樹的實現

#includeusing namespace std;

#define ll long long

#define db double

#define max 10000

#define rep(i,j,k) for(int i=(int)(j);i<=(int)(k);i++)

#define per(i,j,k) for(int i=(int)(j);i>=(int)(k);i--)

void down(int k);

struct node

tree[4*max+1]; //樹必須要開4倍空間

//線段樹基礎操作:

/*1.建樹

2.單點查詢

3.單點修改

4.區間查詢

5.區間修改

*///1. 建樹

void build(int l, int r, int k)

int m = (l + r) / 2;

build(l, m, k * 2);//左孩子

build(m, r, k * 2 + 1);//右孩子

tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w; //區間和 把孩子的區間和加起來就是父節點的區間和

}//2.單點查詢

/*ans是查詢的標誌

x是查詢的值

*/void ask(int k,int ans,int x)

if (tree[k].f) down(k); //懶標記下傳

int mid = (tree[k].l + tree[k].r) / 2;

if (x <= mid)

else }

//3.單點修改

/*在修改後 父節點即以上節點的值都需要更新

y是要+上的值

x是需要修改的值 修改後為x+y

*/void add(int k,int x,int y)

if (tree[k].f) down(k); //懶標記下傳

int mid = (tree[k].l + tree[k].r) / 2;

if (x <= mid)

else

//更新

tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w; //節點更新

}//4.區間查詢

/*思路是:

查詢區間為 [x,y]

mid=(l+r)/2

y<=mid 查詢區間全部在當前區間的左子區間,所以左子女區間走

x>mid 查詢區間全部在當前區間的右子區間,所以右子女區間走

否則 兩個區間走

ans 是查詢之和

*/void sum(int k,int x, int y,int ans)

if (tree[k].f) down(k); //懶標記下傳

int mid = (tree[k].l + tree[k].r) / 2;

if (x <= mid)

if (y > mid) }

//5.區間修改

/*修改一段連續區間的值 給區間[a,b]都加上x

在區間修改的過程中,如果我們從最上層開始修改到最底層 那麼複雜度比線性還高 那麼用線段樹根本就沒有什麼意義

還有就是在查詢的時候 如果我們只查詢上層的區間 那麼我們該層以下的所有區間修改都是白費了,那麼如果層數很多 時間複雜度就上去了

所有我們引入乙個標記

引入懶標記

作用:儲存到這個節點的修改資訊,暫時不把修改資訊傳到子節點。

步驟:a.在結構體中新增新的變數 儲存這個懶標記

b.遞迴到這個節點的時候,只更新這個節點的狀態,並把當前的更改值累計到標記中去。

c.當需要遞迴這個節點的子節點的時候,標記再往下傳遞,這樣我們就減少了不必要的下傳操作,可以理解為你想要多少 下傳多少 當你訪問的時候再下傳

d.下傳操作:

① 當前節點的懶標記 累計 到子節點的懶標記中去

② 修改子節點的狀態。 就是 原狀態+子節點區間點的個數*父節點傳下來的懶標記 相當於就是自己的加上每次父節點上傳下來的

③ 父節點懶標記清0 相當於該標記已經傳到了子節點去了 為了避免重複下傳 所以把父節點清0

*///懶標記下傳**

void down(int k)

//區間修改

void add2(int k, int a, int b, int x)

if (tree[k].f)

int mid = (tree[k].r + tree[k].l) / 2;

if (a <= mid) add2(k * 2, a, b, x);

if (b > mid) add2(k * 2 + 1, a, b, x);

//更改區間狀態

tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;

}int main()

線段樹的實現(模板)

線段樹 在一類問題中,我們需要經常處理可以對映在乙個座標軸上的一些固定線段,例如說對映在ox軸上的線段。由於線段是可以互相覆蓋的,有時需要動態地取線段的並,例如取得並區間的總長度,或者並區間的個數等等。乙個線段是對應於乙個區間的,因此線段樹也可以叫做區間樹。線段樹的構造思想 線段樹是一棵二叉樹,樹中...

線段樹的基本實現

線段樹是這樣一種結構,每個節點儲存陣列一部分的和 原陣列為13 57911 對應的線段樹結構如下 根節點是陣列之和,根節點的左孩子是陣列左半部分之和,根節點的右孩子是陣列右半部分數值之和。中間點 int mid start end 2 int left node 2 node 1 左子樹樹根 int...

RMQ(線段樹實現)

t t第乙個線段樹程式,還沒a過題,不過也很感動,先貼出來 下標從0開始,輸入 1 1 結束.求每一段區間之間的最大值。include include typedef struct treenodenode int mymax int a,int b node buildtree int a,int...