知識點 樹鏈剖分

2022-05-19 03:05:06 字數 2705 閱讀 8322

用於解決一系列維護靜態樹上資訊的問題。這些問題看起來非常像一些區間操作搬到了樹上。

(例如:一棵帶權樹,需要維護修改權值操作以及從$u$到$v$簡單路徑上的權值和)

樹鏈剖分就是通過某種策略(一般是輕、重邊剖分)將原樹鏈劃分成若干條鏈,每條鏈相當於乙個序列,此時就可以用區間資料結構(一般是線段樹)維護這些鏈。

$f(x)$:$x$在樹中的父親。

$dep(x)$:$x$在樹中的深度。

$siz(x)$:$x$的子樹大小。

$son(x)$:$u$的重兒子:在$u$的所有兒子中$siz$值最大的兒子,$u\rightarrow v$為重邊。

($u$的輕兒子:在$u$的所有兒子中除了重兒子以外的兒子,$u\rightarrow v$為輕邊。)

$top(x)$:$x$所在重路徑的頂部節點。

$rnk(x)$:線段樹中$x$位置對應的樹中節點編號,即有$rnk(seg(x))=x$。

1、如果$u\rightarrow v$為輕邊,則$siz(v)<=siz(u)/2$。

證明:反證法,若存在$siz(v)>siz(u)/2$且存在$siz(v_0)>siz(v)$,那麼$siz(v)+siz(v_0)>siz(u)$,即子節點的$siz$和大於父節點的$siz$。

2、從根到任何點$u$的路徑上輕邊的條數不超過$log(n)$。

證明:由1可知從根到$u$的路徑上每經過一條輕邊,當前子樹的節點個數至少會少$\frac$,所以至多減少$log(n)$次$siz$值為0,到達葉節點。

3、從根到任何點$u$的路徑上輕邊、重邊的條數均不超過$log(n)$。

證明:每條重鏈的起點和終點都連線一條輕邊,由2可知輕邊條數不超過$log(n)$,所以重鏈條數也不超過$log(n)$。

1、一遍$dfs$得到前4個值,再一遍$dfs$將樹的節點重新排序,使一條重鏈上的點$dfs$序連續。

2、使用線段樹維護新樹的$dfs$序序列,查詢時沿重鏈走到兩點的$lca$並計算答案。

#include#include

#include

#include

using

namespace

std;

#define maxn 100005

#define maxm 500005

#define inf 0x7fffffff

#define ll long long

int hd[maxn],to[maxn<<1

],top[maxn];

int a[maxn],nxt[maxn<<1

],cnt,tot;

intf[maxn],siz[maxn],son[maxn];

intseg[maxn],rnk[maxn],dep[maxn];

struct nodetr[maxn<<2

];char str[10

];inline

intread()

inline

void add(int u,int

v)inline

void pushup(int

k)inline

void dfs1(int u,int fa,int

d)

return;}

inline

void dfs2(int u,int fa,int

tp)

return;}

inline

void build(int l,int r,int

k)

int mid=(l+r)>>1

; build(l,mid,k

<<1

); build(mid+1,r,k<<1|1

); pushup(k);

return;}

inline

void update(int x,int y,int

k)

int mid=(tr[k].l+tr[k].r)>>1

;

if(x<=mid) update(x,y,k<<1

);

else update(x,y,k<<1|1

); pushup(k);

return;}

inline

int qmx(int l,int r,int

k)inline

int qsum(int l,int r,int

k)inline

int solve1(int u,int

v)

if(dep[u]ans=max(ans,qmx(seg[v],seg[u],1

));

return

ans;

}inline

int solve2(int u,int

v)

if(dep[u]ans+=qsum(seg[v],seg[u],1

);

return

ans;

}int

main()

for(int i=1;i<=n;i++) a[i]=read();

dfs1(

1,0,1);dfs2(1,0,1);build(1,n,1

);

int m=read();

while(m--)

return0;

}

樹鏈剖分 樹鏈剖分講解

好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...

演算法入門 樹鏈剖分 輕重鏈剖分

目錄 3.0 求 lca 4.0 利用資料結構維護資訊 5.0 例題 參考資料 資料結構入門 線段樹 發表於 2019 11 28 20 39 dfkuaid 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查詢 標記下傳 標記永久化 閱讀全文 樹鏈剖分用...

樹鏈剖分 樹剖換根

這是一道模板題。給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...