dsu on tree
,即树上启发式合并。它要满足:
- 只有询问,且是离线(无修改操作)
- 只涉及到子树(或者可以把问题转化为子树上操作)
- 子树之间不会互相干扰
它和莫队的思想其实有一点像,都是“优雅的暴力”
具体的实现过程:
- 对于树上一个节点,先处理轻子树的答案,统计完只影响到,不向上保留
- 再处理重子树答案,统计完不仅会影响到,还要向上保留
- 回溯时,算出轻子树的答案。如果不能保留,则删掉贡献。(函数暴力算)
- 关键思想就是删掉轻儿子,保留重儿子
这样做的时间复杂度是对的,因为一个点到根路径上不超过条轻边
具体代码:
void dfs(int x, int f)
{
sz[x] = 1; int mx = 0;
for (int i = hd[x]; i; i = nxt[i])
{
int y = to[i];
if (y == f) continue;
dep[y] = dep[x] + 1;
dfs(y, x), sz[x] += sz[y];
if (sz[y] > mx) mx = sz[y], ms[x] = y; // 重儿子
}
return;
}
void calc(int x, int f, int o)
{
if (o == 1) // do something (统计子树内答案)
else // do something (消除影响)
for (int i = hd[x]; i; i = nxt[i])
{
int y = to[i];
if (y == f || y == nms) continue;
calc(y, x, o);
}
return;
}
void dsu(int x, int f, int o)
{
for (int i = hd[x]; i; i = nxt[i])
{
int y = to[i];
if (y == f || y == ms[x]) continue;
dsu(y, x, -1); // 轻子树
}
if (ms[x]) dsu(ms[x], x, 1), nms = ms[x]; // 重子树
calc(x, f, 1), nms = 0;
ans[x] = ... // 更新答案
if (o == -1) calc(x, f, -1);
return;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】