Lca樹鏈剖分法

2021-08-06 05:00:56 字數 1422 閱讀 7597

樹鏈剖分各陣列的作用:

son:最重的兒子節點,即節點最多的那個

bulk:所有兒子節點的總和(包括兒子的兒子)

dep:該節點的深度

ft:該節點的父親

top:鏈的最上方的節點

首先dfs預處理出前面的四個陣列。

然後第二個dfs進行剖分,預處理出最後乙個陣列。

例子:

此時son[1]=3(因為bulk[3]=6>bulk[2]=5),son[3]=10,son[4]=5,以此類推。

然後剖分之後相當於變成了

此時top[10]=1,top[7]=7,top[8]=9,以此類推

接下來就是進行lca,假設c=lca(a,b),首先,當a,b在同一條重鏈中時,c=min(dep[a],dep[b]),當a,b不在同一條重鏈中時,畫圖易知c一定是劃分輕重鏈的的那個分支點,比如圖中的1,3,4。假設我們現在要求lca(7,8),那麼lca(7,8)一定是某條直到7,8在同一條重鏈時的分支點,所以不斷地把7,8向上合併到重鏈中,直到他們在同一條重鏈中。

現在進行模擬,先看看**中的lca,方便理解。令x=7,y=8,因為dep[top[x]]>dep[top[y]](top[x]=7,top[y]=9),所以更新x=4,發現top[x](top[x]=2),top[y](top[y]=9)不在一條重鏈中,繼續更新,此時dep[top[y]]大,更新y=3,因為dep[top[x]]大,更新x=1,發現他們已經在同一條重鏈中,那麼深度小的即為lca(7,8)

附模板:

#include

#include

#include

using

namespace

std;

const

int maxn = 1000;

struct edge

}edge[maxn];

int head[maxn], edgenum;//鄰接表

int son[maxn], bulk[maxn], dep[maxn], ft[maxn], top[maxn];

void toinit()

void toadd(int u,int v)

void todfs1(int u,int f,int tier)

}void todfs2(int u,int f,int rt)

}int tolca(int x,int y)

return dep[x] < dep[y] ? x : y;

}int main()

LCA 樹鏈剖分

剛打完lca板子,寫個東西記下 dfs第一遍求出 結點i的深度,以i為根的子樹大小,結點i的父親,並求出重鏈 dfs第二遍求出 結點i所在重鏈的鏈頂 如果在重鏈上 開始lca,兩個點往上找,深度大的點就往上跳,這個點如果在重鏈上,就跳到所在重鏈的鏈頂的父親處,在輕鏈上,就直接跳到自己父親上 洛谷lc...

洛谷 P3379 LCA (樹鏈剖分法)

給出乙個n節點,s為根的樹,m次詢問某兩個節點間的lca n 500000,m 500000 lca的方法一般有倍增,tarjan,樹鏈剖分,這裡主要介紹樹鏈剖分 這個題用vector的樹鏈剖分會超時 常數原因 vector的其他方法,開o2貌似能過 size u 以u為根節點的子樹的節點數 dep...

樹鏈剖分(1) 樹剖求LCA

先看乙個樹剖的經典應用 初始化 先dfs一遍子樹,統計出每乙個點x的重兒子son x 和以x為根節點的子樹的大小siz x 這裡選擇x中子樹大小最大的兒子作為它的重兒子,第二遍dfs劃分樹鏈 重兒子與其父親節點劃分到一條鏈。其他的兒子為x的輕兒子,但屬於新的鏈的頂端元素。void dfs1 int ...