This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub kmyk/competitive-programming-library
/**
* @brief fold a rooted tree / 木DP
* @note O(N op) time
* @note O(N) space, not recursive
* @note
* struct tree_operation {
* typedef int type;
* type operator () (int i, vector<pair<int, type> > const & args);
* };
* @note interfaceちょっと微妙じゃない? どうせ一緒にadd()実装する あと辺に重みがあると修正がつらい
*/
template <typename TreeOperation>
vector<typename TreeOperation::type> fold_rooted_tree(vector<vector<int> > const & g, int root, TreeOperation op = TreeOperation()) {
int n = g.size();
vector<typename TreeOperation::type> data(n);
stack<tuple<bool, int, int> > stk;
stk.emplace(false, root, -1);
while (not stk.empty()) {
bool state; int x, parent; tie(state, x, parent) = stk.top(); stk.pop();
if (not state) {
stk.emplace(true, x, parent);
for (int y : g[x]) if (y != parent) {
stk.emplace(false, y, x);
}
} else {
vector<pair<int, typename TreeOperation::type> > args;
for (int y : g[x]) if (y != parent) {
args.emplace_back(y, data[y]);
}
data[x] = op(x, args);
}
};
return data;
}
/**
* @brief rerooting (全方位木DP)
* @note O(N op) time
* @note O(N) space, not recursive
* @note
* struct tree_operation {
* typedef int type;
* type add(int i, type data_i, int j, type data_j); // add a subtree j to the root i
* type subtract(int i, type data_i, int j, type data_j); // remove a subtree j from the root i
* };
* @note if add & subtract are slow, you can merge them
* @see https://twitter.com/tmaehara/status/980787099472297985
*/
template <typename TreeOperation>
vector<typename TreeOperation::type> reroot_folded_rooted_tree(vector<typename TreeOperation::type> data, vector<vector<int> > const & g, int root, TreeOperation op = TreeOperation()) {
stack<pair<int, int> > stk;
stk.emplace(root, -1);
while (not stk.empty()) {
int x, parent; tie(x, parent) = stk.top(); stk.pop();
if (parent != -1) {
data[x] = op.add(x, data[x], parent, op.subtract(parent, data[parent], x, data[x]));
}
for (int y : g[x]) if (y != parent) {
stk.emplace(y, x);
}
}
return data;
}
// 注意: まだverifyしてない
struct height_tree_operation {
typedef pair<int, int> type;
type operator () (int i, vector<pair<int, type> > const & args) {
type acc = make_pair(INT_MIN, INT_MIN);
for (auto arg : args) {
acc = add(i, acc, arg.first, arg.second);
}
return acc;
}
type add(int i, type data_i, int j, type data_j) { // add a subtree j to the root i
array<int, 3> height = {{ data_i.first, data_i.second, data_j.first + 1 }}; // NOTE: the length is corrent
sort(height.rbegin(), height.rend());
return make_pair(height[0], height[1]);
}
type subtract(int i, type data_i, int j, type data_j) { // remove a subtree j from the root i
if (data_i.first == data_j.first + 1) {
return make_pair(data_i.second, INT_MIN); // NOTE: this is correct
} else {
return data_i;
}
}
};
struct heights_tree_operation {
typedef multiset<int> type; // heights of subtrees
type operator () (int i, vector<pair<int, type> > const & args) {
type data;
for (auto arg : args) {
data = add(i, data, arg.first, arg.second);
}
return data;
}
type add(int i, type data_i, int j, type data_j) { // add a subtree j to the root i
int height = 1 + accumulate(ALL(data_j), 0, [&](int a, int b) { return max(a, b); });
data_i.insert(height);
return data_i;
}
type subtract(int i, type data_i, int j, type data_j) { // remove a subtree j from the root i
int height = 1 + accumulate(ALL(data_j), 0, [&](int a, int b) { return max(a, b); });
auto it = data_i.find(height);
data_i.erase(it);
return data_i;
}
};
unittest {
vector<vector<int> > g(9);
constexpr int root = 0;
g[0].push_back(1);
g[0].push_back(2);
; g[2].push_back(4);
; g[2].push_back(5);
; g[2].push_back(6);
; ; g[6].push_back(8);
g[0].push_back(3);
; g[3].push_back(7);
auto dp1 = fold_rooted_tree(g, root, heights_tree_operation());
auto dp2 = reroot_folded_rooted_tree(dp1, g, root, heights_tree_operation());
assert (dp1[root] == dp2[root]);
assert (dp1[2] == multiset<int>({ 1, 1, 2 }));
assert (dp2[2] == multiset<int>({ 1, 1, 2, 3 }));
assert (dp1[3] == multiset<int>({ 1 }));
assert (dp2[3] == multiset<int>({ 1, 4 }));
}
// 簡略化したやつ 未検証
/**
* @brief fold a rooted tree (木DP)
* @note O(N op) time
* @note O(N) space on stack
* @note
* struct tree_operation {
* typedef int type;
* type unit(int i); // get an initial value of root i
* type add(int i, type data_i, int j, type data_j); // add a subtree j to the root i
* };
* @note you can replace unit() + add() with a single function
*/
template <typename TreeOperation>
vector<typename TreeOperation::type> fold_rooted_tree(vector<vector<int> > const & g, int root, TreeOperation op = TreeOperation()) {
int n = g.size();
vector<typename TreeOperation::type> data(n);
function<void (int, int)> go = [&](int i, int parent) {
data[i] = op.unit(i);
for (int j : g[i]) if (j != parent) {
go(j, i);
data[i] = op.add(i, data[i], j, data[j]);
}
};
go(root, -1);
return data;
}
/**
* @brief rerooting (全方位木DP)
* @note O(N op) time
* @note O(N) space on stack
* @note
* struct tree_operation {
* typedef int type;
* type add(int i, type data_i, int j, type data_j); // add a subtree j to the root i
* type subtract(int i, type data_i, int j, type data_j); // remove a subtree j from the root i
* };
* @note a commutative group is one of the structures for this
* @note you can replace add() + subtract() with a single function
* @see https://twitter.com/tmaehara/status/980787099472297985
*/
template <typename TreeOperation>
vector<typename TreeOperation::type> reroot_folded_rooted_tree(vector<typename TreeOperation::type> data, vector<vector<int> > const & g, int root, TreeOperation op = TreeOperation()) {
function<void (int, int)> go = [&](int i, int parent) {
if (parent != -1) {
data[i] = op.add(i, data[i], op.subtract(parent, data[parent], i, data[i]));
}
for (int j : g[i]) if (j != parent) {
go(j, i);
}
};
go(root, -1);
return data;
}
#line 1 "old/tree-dp.inc.cpp"
/**
* @brief fold a rooted tree / 木DP
* @note O(N op) time
* @note O(N) space, not recursive
* @note
* struct tree_operation {
* typedef int type;
* type operator () (int i, vector<pair<int, type> > const & args);
* };
* @note interfaceちょっと微妙じゃない? どうせ一緒にadd()実装する あと辺に重みがあると修正がつらい
*/
template <typename TreeOperation>
vector<typename TreeOperation::type> fold_rooted_tree(vector<vector<int> > const & g, int root, TreeOperation op = TreeOperation()) {
int n = g.size();
vector<typename TreeOperation::type> data(n);
stack<tuple<bool, int, int> > stk;
stk.emplace(false, root, -1);
while (not stk.empty()) {
bool state; int x, parent; tie(state, x, parent) = stk.top(); stk.pop();
if (not state) {
stk.emplace(true, x, parent);
for (int y : g[x]) if (y != parent) {
stk.emplace(false, y, x);
}
} else {
vector<pair<int, typename TreeOperation::type> > args;
for (int y : g[x]) if (y != parent) {
args.emplace_back(y, data[y]);
}
data[x] = op(x, args);
}
};
return data;
}
/**
* @brief rerooting (全方位木DP)
* @note O(N op) time
* @note O(N) space, not recursive
* @note
* struct tree_operation {
* typedef int type;
* type add(int i, type data_i, int j, type data_j); // add a subtree j to the root i
* type subtract(int i, type data_i, int j, type data_j); // remove a subtree j from the root i
* };
* @note if add & subtract are slow, you can merge them
* @see https://twitter.com/tmaehara/status/980787099472297985
*/
template <typename TreeOperation>
vector<typename TreeOperation::type> reroot_folded_rooted_tree(vector<typename TreeOperation::type> data, vector<vector<int> > const & g, int root, TreeOperation op = TreeOperation()) {
stack<pair<int, int> > stk;
stk.emplace(root, -1);
while (not stk.empty()) {
int x, parent; tie(x, parent) = stk.top(); stk.pop();
if (parent != -1) {
data[x] = op.add(x, data[x], parent, op.subtract(parent, data[parent], x, data[x]));
}
for (int y : g[x]) if (y != parent) {
stk.emplace(y, x);
}
}
return data;
}
// 注意: まだverifyしてない
struct height_tree_operation {
typedef pair<int, int> type;
type operator () (int i, vector<pair<int, type> > const & args) {
type acc = make_pair(INT_MIN, INT_MIN);
for (auto arg : args) {
acc = add(i, acc, arg.first, arg.second);
}
return acc;
}
type add(int i, type data_i, int j, type data_j) { // add a subtree j to the root i
array<int, 3> height = {{ data_i.first, data_i.second, data_j.first + 1 }}; // NOTE: the length is corrent
sort(height.rbegin(), height.rend());
return make_pair(height[0], height[1]);
}
type subtract(int i, type data_i, int j, type data_j) { // remove a subtree j from the root i
if (data_i.first == data_j.first + 1) {
return make_pair(data_i.second, INT_MIN); // NOTE: this is correct
} else {
return data_i;
}
}
};
struct heights_tree_operation {
typedef multiset<int> type; // heights of subtrees
type operator () (int i, vector<pair<int, type> > const & args) {
type data;
for (auto arg : args) {
data = add(i, data, arg.first, arg.second);
}
return data;
}
type add(int i, type data_i, int j, type data_j) { // add a subtree j to the root i
int height = 1 + accumulate(ALL(data_j), 0, [&](int a, int b) { return max(a, b); });
data_i.insert(height);
return data_i;
}
type subtract(int i, type data_i, int j, type data_j) { // remove a subtree j from the root i
int height = 1 + accumulate(ALL(data_j), 0, [&](int a, int b) { return max(a, b); });
auto it = data_i.find(height);
data_i.erase(it);
return data_i;
}
};
unittest {
vector<vector<int> > g(9);
constexpr int root = 0;
g[0].push_back(1);
g[0].push_back(2);
; g[2].push_back(4);
; g[2].push_back(5);
; g[2].push_back(6);
; ; g[6].push_back(8);
g[0].push_back(3);
; g[3].push_back(7);
auto dp1 = fold_rooted_tree(g, root, heights_tree_operation());
auto dp2 = reroot_folded_rooted_tree(dp1, g, root, heights_tree_operation());
assert (dp1[root] == dp2[root]);
assert (dp1[2] == multiset<int>({ 1, 1, 2 }));
assert (dp2[2] == multiset<int>({ 1, 1, 2, 3 }));
assert (dp1[3] == multiset<int>({ 1 }));
assert (dp2[3] == multiset<int>({ 1, 4 }));
}
// 簡略化したやつ 未検証
/**
* @brief fold a rooted tree (木DP)
* @note O(N op) time
* @note O(N) space on stack
* @note
* struct tree_operation {
* typedef int type;
* type unit(int i); // get an initial value of root i
* type add(int i, type data_i, int j, type data_j); // add a subtree j to the root i
* };
* @note you can replace unit() + add() with a single function
*/
template <typename TreeOperation>
vector<typename TreeOperation::type> fold_rooted_tree(vector<vector<int> > const & g, int root, TreeOperation op = TreeOperation()) {
int n = g.size();
vector<typename TreeOperation::type> data(n);
function<void (int, int)> go = [&](int i, int parent) {
data[i] = op.unit(i);
for (int j : g[i]) if (j != parent) {
go(j, i);
data[i] = op.add(i, data[i], j, data[j]);
}
};
go(root, -1);
return data;
}
/**
* @brief rerooting (全方位木DP)
* @note O(N op) time
* @note O(N) space on stack
* @note
* struct tree_operation {
* typedef int type;
* type add(int i, type data_i, int j, type data_j); // add a subtree j to the root i
* type subtract(int i, type data_i, int j, type data_j); // remove a subtree j from the root i
* };
* @note a commutative group is one of the structures for this
* @note you can replace add() + subtract() with a single function
* @see https://twitter.com/tmaehara/status/980787099472297985
*/
template <typename TreeOperation>
vector<typename TreeOperation::type> reroot_folded_rooted_tree(vector<typename TreeOperation::type> data, vector<vector<int> > const & g, int root, TreeOperation op = TreeOperation()) {
function<void (int, int)> go = [&](int i, int parent) {
if (parent != -1) {
data[i] = op.add(i, data[i], op.subtract(parent, data[parent], i, data[i]));
}
for (int j : g[i]) if (j != parent) {
go(j, i);
}
};
go(root, -1);
return data;
}