Dsu on tree
(\(\uparrow\) 学习参考)
一般来说,Dsu on tree 大多可以和 点分治 互相换着用,都是处理子树或以 \(x\) 为根的路径等问题。
这种问题假设好状态基本上可以秒了。
(当然有时候还可以和 长链剖分 互换)
算法结构与模板
首先类似重链剖分的预处理,求出每个点的 \(dfnl,dfnr,bigson\) 等信息。
对于以 \(x\) 为根的一颗子树,在处理答案时这样做:
-
先处理只经过轻儿子的答案,处理完后清空轻儿子的影响。
-
处理经过重儿子的答案,不清空影响。
-
再次处理 \(x\) 的所有轻儿子,不清空影响并记录答案。
-
如果需要清空影响就清空影响。
void solve(int x,int fa,bool Keep)
{
for(int i=hea[x];i;i=nex[i])
if(ver[i]!=fa && ver[i]!=bigson[x])
solve(ver[i],x,false);
// 如果需要,这里同时继承轻儿子的答案
if(bigson[x]) solve(bigson[x],x,true);
// 如果需要,这里同时继承重儿子的答案
// 只经过 x 的答案
for(int i=hea[x];i;i=nex[i])
{
if(ver[i]==fa || ver[i]==bigson[x]) continue;
for(int j=dfnl[ver[i]];j<=dfnr[ver[i]];j++)
// 统计这棵子树的答案与之前子树的答案
for(int j=dfnl[ver[i]];j<=dfnr[ver[i]];j++)
// 将这棵子树的答案加入统计数组
}
if(!Keep) // 需要清除影响
for(int i=dfnl[x];i<=dfnr[x];i++)
// 全部清除答案,可以相当于 memset,不用担
// 心同样状态的其他答案的问题,因为所有答
// 案都是先清除再添加的,只有处理完子树答
// 案才会处理根的答案。
}
例题
CF246E Blood Cousins Return
CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
CF208E Blood Cousins
P4149 [IOI2011]Race
点分治??当然也可以用 dsu on tree 啦!