專題 樹鏈剖分

2022-09-23 07:51:10 字數 2599 閱讀 4965

樹鏈剖分

定義:size[u]表示以節點u為根的子樹的節點個數

我們將乙個節點到它的兒子中size值最大的那個節點的邊定義為重邊,其他邊定義為輕邊

我們稱某條路徑為重路徑(或重鏈)當且僅當它全部由重邊組成

性質:我們可以證明對於每個點到根的路徑上都不超過o(logn)條輕邊和o(logn)條重路徑組成

這種將樹上的邊(路徑)分為重邊(重路徑)和輕邊的做法就稱稱為樹鏈剖分

有了以上定義和樹鏈剖分的概念之後,接下來就是樹鏈剖分可以用來幹什麼的問題了

樹鏈剖分主要是用來處理樹上和路徑有關的問題。

將樹分為若干條鏈的好處就是可以將問題分而治之, 根據前面提到的我們可以將任意兩個點之間的路徑分為為數不多的輕重鏈(邊),很多問題是可以根據這些輕重鏈(邊)的資訊構造來得到答案的。

問題的關鍵是怎麼對這些鏈(邊)中的資訊進行維護

這裡我們需要知道乙個叫dfs序的東西,dfs序相當於就是將樹上的節點對映成乙個線性的序列。但是這裡我們和dfs序不同的一點是,在搜尋的過程中我們先去訪問根節點的重兒子,這樣就可以將一條重路徑上的點對映到乙個連續的序列中了,既然是連續的序列我們就很容易想到通過線段樹來對這個資訊進行維護了。

需要用到的陣列和變數有:

dep[i]表示節點i的深度

size[i]表示以節點i為根的子樹的節點數

son[i]表示節點i的兒子

fa[i]表示節點i的父親

top[i]表示節點i所在重鏈上最高的節點的編號

tid[i]表示i與其父親節點所連邊**段樹中的位置

題目大意

給一棵樹,有兩個操作:

x c 將樹上第x條邊修改值為c u v 查詢樹上兩個節點(u,v)之間的最短路徑上權值最大的一條邊的值**#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

#define ll long long int

const int maxn=20000;

int t;

int n;

int dep[maxn];//儲存節點的深度

int son[maxn];//儲存節點的重兒子

int fa[maxn];//節點的父親

int sz[maxn];//以某個節點為根的子樹中節點的個數

int top[maxn];//top[v]表示節點v所在重鏈上最高的節點的編號

int tid[maxn];//tid[v]表示v與其父親節點所連邊**段樹中的位置

int indx;//用於求dfs序(嚴格來說不叫dfs序,先訪問重兒子的dfs序)時的標號

int maxn[maxn<<2];//線段樹

struct edge

; edge(int u,int v,int w,int next): u(u),v(v),w(w),next(next){}

}edge[maxn*2];

int edgecount;

int head[maxn];

void init()

inline void add_edge(int u,int v,int w)

void dfs1(int u)//初始化dep son fa sz陣列

}void dfs2(int u,int ance)//初始化top tid陣列 ance表示重鏈的頂端節點

}///線段樹部分

inline void pushup(int rt)

void update(int pos,int x,int l,int r,int rt)//將pos改為x

int m=(l+r)/2;

if(m>=pos)update(pos,x,l,m,rt*2);

else update(pos,x,m+1,r,rt*2+1);

pushup(rt);

}int query(int l,int r,int l,int r,int rt)//查詢區間[l,r]的最大值

int solve(int u,int v)//查詢兩個節點u v的最短路徑上的最大權值的邊

//調整成ance_u在上面

maxm=max(maxm,query(tid[ance_v],tid[v],1,indx,1));

v=fa[ance_v];

ance_v=top[v];

}if(u==v)return maxm;

if(dep[v] < dep[u])return max(maxm,query(tid[son[v]],tid[u],1,indx,1));//v在上面

else return max(maxm,query(tid[son[u]],tid[v],1,indx,1));//u在上面

}int main()

{ int a,b,c;

char op[20];

scanf("%d",&t);

while(t--)

{init();

scanf("%d",&n);

for(int i=1;i

專題 樹鏈剖分

include include include include include include include include include include using namespace std define ll long long int const int maxn 20000 int t...

樹鏈剖分 樹鏈剖分講解

好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 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...

樹鏈剖分 專題,學習記錄

理解了上面的那個部落格中的想法之後,你可以看這個神犇寫的 spoj上的 第一版 調了一下午 半晚上,第一次a的時候那真是excited include include include include include include using namespace std typedef long l...