樹鏈剖分詳解 luoguP3384【模板】樹鏈剖分
阿新 • • 發佈:2019-03-05
class -s 結點 問題 父節點 tro dfs 詳解 tip
一:用處
對一棵樹分成幾條鏈,把樹形變為線性,減少處理難度
需要處理的問題:
1.將樹從x到y結點最短路徑上所有節點的值都加上z
2.求樹從x到y結點最短路徑上所有節點的值之和
3.將以x為根節點的子樹內所有節點值都加上z
4.求以x為根節點的子樹內所有節點值之和
二:相關概念:
1.重兒子:對於每一個非葉子節點,它的兒子中以那個兒子為根的子樹節點數(包括自身)最大的兒子為該節點的重兒子
2.輕兒子:非重兒子
3.重邊:一個父節點與其重兒子的連邊
4.輕邊:非重邊
5.重鏈:相鄰重邊相連形成的鏈
tips:葉子結點若為輕兒子,則自成一條長度為1的鏈
重鏈以輕兒子或根節點為起點
三:常規操作
1.預處理
(1)dfs1:
處理:
各點深度; 各點重兒子編號; 各點最大子樹大小 ;各點父親
代碼:
void dfs1(int now,int fa,int deep)
{
siz[now]=1;
fat[now]=fa;
dep[now]=deep;
zs=-1;
for(int i=head[now];i;i=nxt[i])
{
if(to[i]==now)
continue; //別忘了
dfs1(to[i],now,deep+1 );
siz[now]+=siz[to[i]];
if(siz[to[i]]>zs)//處理重兒子
zhoson[now]=to[i],zs=siz[to[i]];
}
}
(2)dfs2
處理:
標記每個點的新編號
賦值每個點的初始值到新編號上
處理每個點所在鏈的頂端
處理每條鏈
順序規定:先重後輕
代碼:
void dfs2(int now,int top) { tp[now]=top; id[now]=++cnt; wt[cnt]=w[x]; if(!zhoson[now]) return; dfs2(zhoson[now],top); for(int i=head[now];i;i=nxt[i]) { if(to[i]==fat[now]||to[i]==zhoson[now]) continue; dfs2(to[i],to[i]); } }
樹鏈剖分詳解 luoguP3384【模板】樹鏈剖分