一、線段樹求子節點
二叉樹的特性:二叉樹裡,每個父親節點的編號為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,右節點編號為...