線段樹1 學習筆記

2021-09-25 03:11:45 字數 3503 閱讀 9289

一、線段樹求子節點

二叉樹的特性:二叉樹裡,每個父親節點的編號為k,則他的兩個兒子節點的編號分別為2k,2k+1。

通過這個特性可以求出父親節點的兩個兒子,且保持用時為o(1):

#define ll long long

inline ll leftson(ll p) //左兒子

inline ll rightson(ll p) //右兒子

二、維護線段樹

push up操作的目的是為了維護父子節點之間的邏輯關係,因為每個節點都要遍歷一遍。所以,開始向線段樹的底層遞迴的時候,要先維護。實際上,push up函式是在合併兩個兒子節點。

#define ll long long

#define maxn 1000001

ll a[maxn],ans[maxn<<2],tag[maxn<<2];

void push_up(ll p)

三、建立線段樹

這裡建立線段樹就要用到所有函式中十分重要的build函式了

#define ll long long

void build(ll p,ll l,ll r)

//因為是從線段樹底層往上回溯,所以,只有線段樹的葉子節點才會被賦值(真正的),`如果左右的區間相同,那麼一定是葉子節點

ll mid=(l+r)>>1;

build(leftson(p),1,mid);

build(rightson(p),mid+1,r);

//這步是二分,如果不二分,就會t飛掉。。。

//把當前根節點的兒子分別當成新節點,繼續建立線段樹

push_up(p);

//當然一定要維護啦……

}

(1)區間修改

#define ll long long

inline void f(ll p,ll l,ll r,ll k)

//區間修改區間修改,先要有區間啊,所以,f函式的存在就能……

// f函式的目的,就是記錄下當前節點的區間,最後呼叫的時候可以直接用f函式,這也是f函式唯一的目的

#define ll long long

inline void push_down(ll p,ll l,ll r)

// push_down函式的存在,就是要呼叫f函式,每次更新兒子節點,然後繼續往下,更新

重磅推出所有函式(9個)中最重要的函式之一:

這個操作的時間複雜度為o(logn)

#define ll long long

inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k)

push_down(p,l,r);

//push_down函式更新所有的葉子節點

ll mid=(l+r)>>1;

if(nl<=mid)update(nl,nr,l,mid,ls(p),k);

//繼續下乙個節點

if(nr>mid) update(nl,nr,mid+1,r,rs(p),k);

//繼續下乙個節點

push_up(p);

//最後當然要維護線段樹了

}

重磅推出最重要的函式之二:

ll query(ll q_x,ll q_y,ll l,ll r,ll p)

打到這累死人了……,線段樹果然名不虛傳

最後貼一波完整的**……

#include#include#define maxn 1000001

#define ll long long

using namespace std;

ll n,m,a[maxn],ans[maxn<<2],tag[maxn<<2];

inline ll leftson(ll x)

inline ll rightson(ll x)

void scan()

inline void push_up(ll p)

void build(ll p,ll l,ll r)

ll mid=(l+r)>>1;

build(leftson(p),l,mid);

build(rightson(p),mid+1,r);

push_up(p);

} inline void f(ll p,ll l,ll r,ll k)

inline void push_down(ll p,ll l,ll r)

inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k)

push_down(p,l,r);

ll mid=(l+r)>>1;

if(nl<=mid)update(nl,nr,l,mid,leftson(p),k);

if(nr>mid) update(nl,nr,mid+1,r,rightson(p),k);

push_up(p);

}ll query(ll q_x,ll q_y,ll l,ll r,ll p)

int main()

case 2:}}

return 0;

}

最後補發鬼畜的壓行**~~~

#include#define ll long long

#define mid ((l+r)>>1)

ll n,m,a[1000001],ans[1000001<<2],tag[1000001<<2];

inline ll leftson(ll p)

inline ll rightson(ll p)

void scan()}

inline void push_up(ll p)

void build(ll p,ll l,ll r)build(leftson(p),l,mid);build(rightson(p),mid+1,r);push_up(p);}

void f(ll p,ll l,ll r,ll k)

inline void push_down(ll p,ll l,ll r)

inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k)push_down(p,l,r);

if(nl<=mid)if(nr>mid)push_up(p);}

ll query(ll q_x,ll q_y,ll l,ll r,ll p)push_down(p,l,r);

if(q_x<=mid) res+=query(q_x,q_y,l,mid,leftson(p));

if(q_y>mid) res+=query(q_x,q_y,mid+1,r,rightson(p));return res;}

int main()

case 2:}}}

感謝洛谷

感謝noi noip 提供了比賽的機會

線段樹學習筆記

線段樹是一種 二叉搜尋樹 與區間樹 相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。使用線段樹可以快速的查詢某乙個節點在若干條線段中出現的次數,時間複雜度為o logn 而未優化的 空間複雜度 為2n,因此有時需要離散化讓空間壓縮。以下筆記摘自lcomyn神犇部落格 1....

線段樹學習筆記

本文筆記在參考一步一步理解線段樹 tenos的基礎上形成 線段樹,也是二叉搜尋樹的一種,是基於陣列,但是優於陣列的一種資料結構。同時結合預處理 時間複雜度一般在o n 使得從原來陣列的o n 的查詢和更新複雜度降到了o logn 在處理很大資料量的資料更新和查詢最值方面變得簡單,值得一提的是,它的構...

線段樹學習筆記

線段樹是一種維護區間的資料結構,且滿足二叉樹的全部性質 下圖是一棵維護區間 1 6 1,6 的線段樹 格式 idl ri dl r我們可以發現,對於每個節點 k k 來說,其左節點編號為2k role presentation style position relative 2k2 k,右節點編號為...