dsu_on_tree.hpp¶
先处理轻子树并清空,再保留重子树、合并轻子树;用加入、查询、删除三个回调统计子树或跨子树贡献。
Complexity: Time: \(O(n \log n)\) callback invocations; Space: \(O(n)\).
Implementation¶
当前头文件,省略 include guard;依赖见 #include。
/// @complexity Time: O(n log n) callback invocations; Space: O(n).
#include <vector>
namespace noya {
/// @brief DSU on a tree rooted at 0; empty input is a no-op, g is unchanged.
/// add(x) inserts x, qry(u,x) queries its contribution at u, del(x) removes x.
/// Query a whole light subtree before adding it; qry(u,u) precedes add(u).
/// Keep the root's final state. Recursion depth is O(tree height).
void dsu_on_tree(std::vector<std::vector<int>> &g, auto &&add, auto &&qry,
auto &&del) {
if (g.empty()) return;
std::vector<int> son(g.size(), -1);
auto init = [&](auto &self, int u, int p) -> int {
int sz = 1, best = 0;
for (int v : g[u]) if (v != p) {
int s = self(self, v, u);
sz += s;
if (s > best) best = s, son[u] = v;
}
return sz;
};
init(init, 0, -1);
// Visit a subtree in heavy-first order, preserving callback order.
auto walk = [&](auto &self, int u, int p, auto &f) -> void {
f(u);
if (son[u] != -1) self(self, son[u], u, f);
for (int v : g[u])
if (v != p && v != son[u]) self(self, v, u, f);
};
auto dfs = [&](auto &self, int u, int p, bool keep) -> void {
for (int v : g[u])
if (v != p && v != son[u]) self(self, v, u, false);
if (son[u] != -1) self(self, son[u], u, true);
auto query = [&](int x) { qry(u, x); };
for (int v : g[u]) if (v != p && v != son[u]) {
walk(walk, v, u, query);
walk(walk, v, u, add);
}
qry(u, u);
add(u);
if (!keep) walk(walk, u, p, del);
};
dfs(dfs, 0, -1, true);
}
} // namespace noya
// NOYA_DSU_ON_TREE_HPP
#ifndef NOYA_DSU_ON_TREE_HPP
#define NOYA_DSU_ON_TREE_HPP 1
/// @complexity Time: O(n log n) callback invocations; Space: O(n).
#include <vector>
namespace noya {
/// @brief DSU on a tree rooted at 0; empty input is a no-op, g is unchanged.
/// add(x) inserts x, qry(u,x) queries its contribution at u, del(x) removes x.
/// Query a whole light subtree before adding it; qry(u,u) precedes add(u).
/// Keep the root's final state. Recursion depth is O(tree height).
void dsu_on_tree(std::vector<std::vector<int>> &g, auto &&add, auto &&qry,
auto &&del) {
if (g.empty()) return;
std::vector<int> son(g.size(), -1);
auto init = [&](auto &self, int u, int p) -> int {
int sz = 1, best = 0;
for (int v : g[u]) if (v != p) {
int s = self(self, v, u);
sz += s;
if (s > best) best = s, son[u] = v;
}
return sz;
};
init(init, 0, -1);
// Visit a subtree in heavy-first order, preserving callback order.
auto walk = [&](auto &self, int u, int p, auto &f) -> void {
f(u);
if (son[u] != -1) self(self, son[u], u, f);
for (int v : g[u])
if (v != p && v != son[u]) self(self, v, u, f);
};
auto dfs = [&](auto &self, int u, int p, bool keep) -> void {
for (int v : g[u])
if (v != p && v != son[u]) self(self, v, u, false);
if (son[u] != -1) self(self, son[u], u, true);
auto query = [&](int x) { qry(u, x); };
for (int v : g[u]) if (v != p && v != son[u]) {
walk(walk, v, u, query);
walk(walk, v, u, add);
}
qry(u, u);
add(u);
if (!keep) walk(walk, u, p, del);
};
dfs(dfs, 0, -1, true);
}
} // namespace noya
#endif // NOYA_DSU_ON_TREE_HPP
/// @complexity Time: O(n log n) callback invocations; Space: O(n).
#include <vector>
namespace noya {
/// @brief DSU on a tree rooted at 0; empty input is a no-op, g is unchanged.
/// add(x) inserts x, qry(u,x) queries its contribution at u, del(x) removes x.
/// Query a whole light subtree before adding it; qry(u,u) precedes add(u).
/// Keep the root's final state. Recursion depth is O(tree height).
void dsu_on_tree(std::vector<std::vector<int>> &g, auto &&add, auto &&qry,
auto &&del) {
if (g.empty()) return;
std::vector<int> son(g.size(), -1);
auto init = [&](auto &self, int u, int p) -> int {
int sz = 1, best = 0;
for (int v : g[u]) if (v != p) {
int s = self(self, v, u);
sz += s;
if (s > best) best = s, son[u] = v;
}
return sz;
};
init(init, 0, -1);
// Visit a subtree in heavy-first order, preserving callback order.
auto walk = [&](auto &self, int u, int p, auto &f) -> void {
f(u);
if (son[u] != -1) self(self, son[u], u, f);
for (int v : g[u])
if (v != p && v != son[u]) self(self, v, u, f);
};
auto dfs = [&](auto &self, int u, int p, bool keep) -> void {
for (int v : g[u])
if (v != p && v != son[u]) self(self, v, u, false);
if (son[u] != -1) self(self, son[u], u, true);
auto query = [&](int x) { qry(u, x); };
for (int v : g[u]) if (v != p && v != son[u]) {
walk(walk, v, u, query);
walk(walk, v, u, add);
}
qry(u, u);
add(u);
if (!keep) walk(walk, u, p, del);
};
dfs(dfs, 0, -1, true);
}
} // namespace noya
// NOYA_DSU_ON_TREE_HPP