1. 程式人生 > >樹鏈剖分詳解 luoguP3384【模板】樹鏈剖分

樹鏈剖分詳解 luoguP3384【模板】樹鏈剖分

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【模板】樹鏈剖分