洛谷 P3379 LCA (樹鏈剖分法)

2021-10-02 16:40:27 字數 2476 閱讀 3188

給出乙個n節點,s為根的樹,m次詢問某兩個節點間的lca

n<=500000,m<=500000

lca的方法一般有倍增,tarjan,樹鏈剖分,這裡主要介紹樹鏈剖分

這個題用vector的樹鏈剖分會超時(常數原因)

vector的其他方法,開o2貌似能過

size[u]:以u為根節點的子樹的節點數

dep[u]:u結點的深度,樹根為0,往下依層遞增

樹鏈剖分是對樹上的邊按規則進行一些劃分:

重邊:節點與其重兒子(所有兒子中size最大的)所連邊

輕邊:節點與其非重兒子連邊

重鏈:重邊相連

輕鏈:輕邊

經過規則,發現重鏈的dep一定是單調的,即不會有這樣的重鏈:(粗邊是重鏈)

應當是這樣的:

引入乙個top[u],如果u在重鏈上,則top[u]能跳到這條重鏈上dep最小的那個點,對於輕鏈,會跳到自己頭上。

這些構建完成後,樹鏈剖分滿足定理:從根到任意乙個點,中間的重鏈數和輕鏈數均不會超過log n

在求lca時,如果乙個個節點跑,那麼面對m次查詢就會很差,甚至一次就需要n次計算。

但是樹鏈剖分中,可以在重鏈上跳,就大大縮短了計算的次數,意思就是如果當前點處於乙個重鏈上,可以直接跳到重鏈的top,直到兩者的top相同(即處在同一條重鏈上/處於同乙個輕邊的同乙個端點)

用fa陣列進行迭代,fa[top[u]]即可不論輕重邊一直跳。

中間過程都讓深度更大的乙個優先往上跳(淺的優先跳會跳的過多導致非「最近」公共祖先)

終止條件即兩個點跳到了同一條重鏈上/乙個輕點上,dep的單調性導致了兩個不同重鏈之間至少有乙個輕鏈,也就不會跳得太多

具體的過程需要兩個dfs,第一次先標記出son,第二次連線起來這些son

結構體存邊版

#include

"cstdlib"

#include

"cstdio"

#include

"iostream"

#include

"vector"

using

namespace std;

#define maxn 500005

int dep[maxn]

, fa[maxn]

, son[ maxn ]

, size [ maxn ]

, top [ maxn ]

;#define cur v[i].t

struct edge

v[maxn<<1]

;int last[maxn]

;void

dfs1

(int x )

}void

dfs2

(int x ,

int t)

inline

intread()

int tot =0;

inline

void

insert

(int

&from ,

int&to)

intmain()

dfs1

(s);

dfs2

(s ,s)

;for

(register

int i =

0; i < m ; i++

)printf

("%d\n"

,dep[f]

?f:g);}

return0;

}

類封裝+vector存邊(不開o2 t3個點,開o2,t2個點)

#include

#include

#include

using

namespace std;

class

tree_chain}}

void

dfs2

(int x,

int t)

//當前節點x,當前重鏈頂的編號

}void

insert

(int

&u,int

&v)int

lca(

int&u,

int&v)

return dep[u]

< dep[v]

? u : v;

}}tc;

intmain()

tc.dfs1

(s);

tc.dfs2

(s, s)

;for

(register

int i =

0; i < m; i++

)return0;

}

洛谷 P3379 LCA 模板題

傳送門 什麼是lca?具體請檢視下面鏈結 這是一道模板題。卡vector,卡cin.所以老實點用鄰接表和scanf把 上面說的很詳細啦 用的是倍增。暴力的優化。鬼知道我理解倍增理解了一下午emmm。主要是儲存和優化位置 然後!自信滿滿以為理解了。開始寫部落格了。發現。似乎?又什麼都不會了。我的內心 ...

樹鏈剖分求LCA的模板(洛谷P3379)

2020.5.6 題目描述我就不寫了,模板題。之前寫過倍增 tarjan求lca的板子,但是倍增這東西我貌似還沒太搞懂,只寫過st表,可能是我太菜了嗚嗚嗚。樹剖其實我之前也沒太弄懂,後來做了一道河南某年的省選題就豁然開朗了 但還沒ac,可能是我用的線段樹板子出問題了 就是用2遍dfs處理好樹內邊的歸...

Lca樹鏈剖分法

樹鏈剖分各陣列的作用 son 最重的兒子節點,即節點最多的那個 bulk 所有兒子節點的總和 包括兒子的兒子 dep 該節點的深度 ft 該節點的父親 top 鏈的最上方的節點 首先dfs預處理出前面的四個陣列。然後第二個dfs進行剖分,預處理出最後乙個陣列。例子 此時son 1 3 因為bulk ...