先看乙個樹剖的經典應用:
初始化:
先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 之後,下文只利用樹鏈剖分求樹上兩點的最...