對於樹進行輕重鏈剖分,對於節點 $x$ ,遞迴所有輕兒子後消除其影響,遞迴重兒子,不消除其影響。
然後對於所有輕兒子的子樹暴力,從而得到 $x$ 的答案。
對於要消除暴力消除即可。
可以發現如果暴力到點 $u$ 必然是其 $u$ 到根的輕邊數量,從而時間複雜度除在統計每個節點答案時其餘時間複雜度為 $o(n\log n)$ 。
cf 600e lomsat gelral
模板題,按上述過程模擬即可。
#include#includeview code#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;
}
或者可以線段樹合併,利用線段樹維護顏色個數。
cf 1009f dominant indices
可以長鏈剖分也可以 $dsu$ ,$dsu$ 的時間複雜度 $o(n\log n)$ 。
#include#includeview code#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
*/
對於重兒子為 $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...