樹鏈剖分(1) 樹剖求LCA

2021-08-29 16:14:09 字數 1223 閱讀 6759

先看乙個樹剖的經典應用:

初始化:

先dfs一遍子樹,統計出每乙個點x的重兒子son[x]和以x為根節點的子樹的大小siz[x],這裡選擇x中子樹大小最大的兒子作為它的重兒子,第二遍dfs劃分樹鏈:重兒子與其父親節點劃分到一條鏈。其他的兒子為x的輕兒子,但屬於新的鏈的頂端元素。

void dfs1(int x,int father,int dep)//主要統計siz和son 

}void dfs2(int x,int anc)//劃分樹鏈

//anc:點x所屬的鏈的頂端節點

初始完之後如何求lca(x,y):

當x和y不屬於一條鏈時,將所屬鏈的頂端節點深度更大(deep[top]值更大的)的點向上提。直到x和y屬於一條鏈為止。此時它們的lca就是x和y中深度更淺的那個。

int lca(int x,int y)

if(deep[top[x]]>deep[top[y]])

} if(deep[x]>=deep[y]) return y;

return x;

}

這樣我們就實現完了樹剖求lca。

完整**(p3379 【模板】最近公共祖先(lca)):

#include#include#define ri register int

using namespace std;

const int maxn=1000020;

int n,q,s,m,u[maxn],v[maxn],fst[maxn],nxt[maxn],xi,yi;

int fa[maxn],deep[maxn],siz[maxn],cur[maxn],son[maxn],top[maxn];

void dfs1(int x,int father,int dep)

}void dfs2(int x,int anc)

int lca(int x,int y)

if(deep[top[x]]>deep[top[y]])

}if(deep[x]>=deep[y]) return y;

return x;

}int main()

dfs1(s,s,0);

dfs2(s,s);

for(ri i=1;i<=q;i++)

return 0;

}

樹鏈剖分求LCA

這裡先推薦兩道練習的裸題 首先是求點 codevs4605 lca 就是求兩個點的公共祖先,每次詢問xor上上乙個詢問的答案。先是兩遍dfs dfs1 把dep siz son求出來 dfs2 求出top和w siz v 表示以v為根的子樹的節點數 dep v 表示v的深度 根深度為1 top v ...

樹鏈剖分求lca

題目描述 給一棵有根樹,以及一些詢問,每次詢問樹上的2 個節點a b,求它們的最近公共祖先.輸入第一行乙個整數n.接下來n 個數,第i 個數fi 表示i 的父親是fi.若fi 0,則i 為樹根.接下來乙個整數m.接下來m 行,每行2 個整數a b,詢問節點 a xor lastans bxor la...

樹鏈剖分 入門(求LCA)

顧名思義,樹鏈剖分就是將樹剖分成一條一條的鏈,之後快速的操作鏈。樹鏈剖分的複雜度為,預處理兩遍dfs,o n 複雜度 之後查詢或者修改操作每一條鏈為o log n 因為剖分出來的鏈一共有log n 條,當然如果在鏈上再套個線段樹,那每次操作就是o log2 n 之後,下文只利用樹鏈剖分求樹上兩點的最...