我們可以把乙個樹剖分為若干條鏈,按照如下規則剖分可以得到的結論是:樹上任意兩點間的的鏈數一定不超過log
nlog_n
logn
條。證明略。
具體的**可以這樣實現:
void
dfs1
(int x,
int fa)
return
;}
由於樹鏈剖分的作用是處理樹上的路徑問題,因此我們有必要通過樹鏈剖分將樹轉化為鏈。
如果我們進行深度優先遍歷,且優先遍歷重兒子,那麼一條路徑一定可以在樹的dfs序中分成連續的若干段。我們也可以藉此記錄每一段----的段頭。
就像這樣:
void
dfs2
(int x,
int cur)
r[x]
= tot;
return
;}
如果我們需要處理想點間的路徑操作,我們可以這樣實現:
樹鏈剖分很模板的一道題,我們只要在dfs序上用線段樹維護即可。
具體見**:
#include
#define int long long
using
namespace std;
const
int n =
200000
;int n, tot =
0, m;
int val[n]
, deep[n]
, size[n]
;int son[n]
, fa[n]
, pos[n]
, top[n]
, dfn[n]
;vector <
int> a[n]
;struct segment t[n*4]
;void
dfs(
int x,
int f)
return;}
void
dfs1
(int x,
int cur)
void
build
(int p,
int l,
int r)
int mid = l+r >>1;
build
(p*2
,l,mid)
;build
(p*2+1
,mid+
1,r)
; t[p]
.sum = t[p*2]
.sum+t[p*2+
1].sum;
t[p]
.max =
max(t[p*2]
.max,t[p*2+
1].max)
;return;}
void
change
(int p,
int x,
int v)
int mid = t[p]
.l+t[p]
.r >>1;
if(x <= mid)
change
(p*2
,x,v);if
(x > mid)
change
(p*2+1
,x,v)
; t[p]
.sum = t[p*2]
.sum+t[p*2+
1].sum;
t[p]
.max =
max(t[p*2]
.max,t[p*2+
1].max)
;return;}
intask_max
(int p,
int l,
int r)
intask_sum
(int p,
int l,
int r)
void
query_max
(int x,
int y)
if(deep[x]
> deep[y]
) x ^
= y ^
= x ^
= y;
ans =
max(ans,
ask_max(1
,pos[x]
,pos[y]))
;printf
("%lld\n"
, ans)
;return;}
void
query_sum
(int x,
int y)
if(deep[x]
> deep[y]
) x ^
= y ^
= x ^
= y;
ans +
=ask_sum(1
,pos[x]
,pos[y]);
printf
("%lld\n"
, ans)
;return;}
signed
main
(void
)for
(int i=
1;i<=n;
++i)
scanf
("%lld"
, val+i)
;dfs(1
,0),
dfs1(1
,1),
build(1
,1,n);
scanf
("%lld"
,&m)
;while
(m --
)return0;
}
樹鏈剖分原理與應用
樹鏈剖分這個演算法我看了好多大神們的部落格,才慢慢領悟,希望我寫的過得去 眾所周知,維護區間資訊的題目可以用線段樹高效實現。類似於區間這樣一維的結構,在樹上維護兩點間的資訊 比如樹上兩點之間的最大值 也可以用線段樹嗎?仔細想想,好像很難實現。因為線段樹維護的是鏈狀結構,而樹是一張圖。但我們想想,如果...
樹鏈剖分原理
樹鏈剖分用一句話概括就是 把一棵樹剖分為若干條鏈,然後利用資料結構 樹狀陣列,sbt,splay,線段樹等等 去維護每一 條鏈,複雜度為o logn 那麼,樹鏈剖分的第一步當然是對樹進行輕重邊的劃分。定義size x 為以x為根的子樹節點個數,令v為u的兒子中size值最大的節點,那麼 u,v 就是...
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 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...