dsu on tree 與長鏈剖分

2022-05-08 19:27:09 字數 3061 閱讀 9302

對於樹進行輕重鏈剖分,對於節點 $x$ ,遞迴所有輕兒子後消除其影響,遞迴重兒子,不消除其影響。

然後對於所有輕兒子的子樹暴力,從而得到 $x$ 的答案。

對於要消除暴力消除即可。

可以發現如果暴力到點 $u$ 必然是其 $u$ 到根的輕邊數量,從而時間複雜度除在統計每個節點答案時其餘時間複雜度為 $o(n\log n)$ 。

cf 600e lomsat gelral

模板題,按上述過程模擬即可。

#include#include

#include

#include

#define int long long

using

namespace

std;

inline

intread()

while(c>='

0'&&c<='9')

return ans*f;

}const

int maxn=100001

;struct

nodex[maxn

<<1

];int

head[maxn],cnt,n,a[maxn];

void add(int u,int

v)int

cnt[maxn],mx,sum,ans[maxn],v,siz[maxn],son[maxn];

void dfs(int u,int

fath)

return;}

void dfs1(int u,int fath,int

w)return;}

void dfs(int u,int fath,int

opt)

if(son[u]) dfs(son[u],u,1

); v=son[u];dfs1(u,fath,1

); ans[u]=sum;

if(!opt) v=0,dfs1(u,fath,-1),mx=sum=0;}

signed main()

dfs(

1,0);dfs(1,0,0

);

for(int i=1;i<=n;i++) printf("

%lld

",ans[i]);printf("\n"

);

return0;

}

view code

或者可以線段樹合併,利用線段樹維護顏色個數。

cf 1009f dominant indices

可以長鏈剖分也可以 $dsu$ ,$dsu$ 的時間複雜度 $o(n\log n)$ 。

#include#include

#include

#include

using

namespace

std;

inline

intread()

while(c>='

0'&&c<='9')

return f*ans;

}const

int maxn=1000001

;struct

nodex[maxn

<<1

];int

dep[maxn],cnt,siz[maxn],son[maxn],n,head[maxn];

intans[maxn];

void add(int u,int

v)void dfs0(int u,int

fath)

return;}

intnum[maxn],mx,sum,lim;

void add(int u,int fath,int

w)return;}

void dfs1(int u,int fath,int

opt)

if(son[u]) dfs1(son[u],u,1);lim=son[u];

add(u,fath,

1);ans[u]=sum;

lim=0

;

if(!opt) add(u,fath,-1),mx=sum=0

;

return;}

intmain()

dfs0(

1,0);dfs1(1,0,0

);

for(int i=1;i<=n;i++)

return0;

}/*81 2

2 31 4

3 54 6

5 74 8

*/

view code

對於重兒子為 $u$ 下面最深的鏈所在兒子,可以發現最多到根有 $\sqrt$ 個長鏈與短鏈,因為對於每次走到輕邊必加上比他深的兒子,可以寫成 $1+2+…x=n->x=\sqrt$ 。

如果乙個子樹 $dp$ 只與深度有關,則可能可以使用長鏈剖分的方法優化它的複雜度。

詳細情況請參考 $link$ 。考慮對於繼承每個重兒子的話可以用指標維護,或者陣列對映即可。

cf 1009f dominant indices

雖然可以 $dsu$ ,但是通過長鏈剖分可以得到更優的複雜度 $o(n)$ 。時間複雜度為 $o(n)$ 因為每條重鏈只統計一次。

「poi2014」酒店 hotel

$n\leq 10^5$ 。考慮 $o(n^2)$ 的樹形 $dp$ ,設 $f_$ 表示在以 $i$ 為根的子樹下到 $i$ 距離為 $j$ 的點的個數,$g_$ 表示在以 $i$ 為根的子樹上有多少個點對需要經過 $i$ 號點後再走 $j$ 步。

轉移考慮當前子樹對另一顆子樹的貢獻與自己的貢獻即可。可以發現 $dp$ 的第二維只與深度有關,並且支援合併,長鏈剖分即可。

乙個小建議就是空間可以多開一點。

[wc2010] 重建計畫

可以發現將答案二分以後分數規劃問題就轉換成邊數在 $[l,r]$ ,且邊權和大於等於 $0$ 是否有解。

考慮將點對答案在 $lca$ 處處理,維護 $f_$ 表示以 $i$ 為根的子樹下到 $i$ 經過 $j$ 條邊的最大邊權。而需要做的是 $f$ 一段區間的 $max$ 。

很顯然 $f$ 陣列支援長鏈剖分,而 $max$ 操作無法通過指標維護,考慮利用陣列對映,同時建線段樹維護極值。

長鏈剖分隨想

之前寫了那麼長一篇blog 現在不如寫篇小短文 說一下另一種樹鏈剖分方法 長鏈剖分的事情。它可以比重鏈剖分更快地完成一些東西。樹鏈剖分的原始版本重鏈剖分非常經典,這裡就不從頭介紹了。原本的剖分方法是按照子樹大小剖分,與子樹點數最多的兒子連成鏈,所以叫做重鏈剖分 然後顯然就有乙個點到根的路徑上至多 o...

長鏈剖分隨想

之前寫了那麼長一篇blog 現在不如寫篇小短文 說一下另一種樹鏈剖分方法 長鏈剖分的事情。它可以比重鏈剖分更快地完成一些東西。樹鏈剖分的原始版本重鏈剖分非常經典,這裡就不從頭介紹了。原本的剖分方法是按照子樹大小剖分,與子樹點數最多的兒子連成鏈,所以叫做重鏈剖分 然後顯然就有乙個點到根的路徑上至多 o...

關於長鏈剖分

看這樣乙個題 dsu on the tree 給你一棵樹,每個節點有一種顏色,問你每個子樹x的顏色數最多的那種顏色,如果顏色數相同,那麼種類數相加。考慮最暴力的暴力,對於每個點遍歷它的子樹,統計答案,然後再撤銷。但是這樣太傻了,每個點顯然可以繼承乙個兒子的資訊,我們選擇繼承它的重兒子的資訊,只 df...