This documentation is automatically generated by online-judge-tools/verification-helper
根付き木の各部分木を同型性で分類する。
各頂点 v について、その部分木の同型類 id を返す。
TreeHash th(n)
n 頂点の木を作るvoid add_edge(int u, int v)
無向辺を追加するvector<int> build(int root = 0)
root を根として部分木 id を構築して返すint th[v]
頂点 v の部分木 id を返すint kinds()
異なる部分木の個数を返す辺をすべて追加してから build(root) を呼ぶ。
返る id は同じ build の中でのみ意味を持ち、id[v] == id[u] のときに限って
v と u の部分木は同型である。
TreeHash th(n);
for (auto [u, v] : edges) th.add_edge(u, v);
auto id = th.build(0);
struct TreeHash {
int n;
vector<vector<int>> g;
vector<int> parent, order, hash_id;
int kind_count;
explicit TreeHash(int n)
: n(n), g(n), parent(n, -1), hash_id(n, -1), kind_count(0) {}
void add_edge(int u, int v) {
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> build(int root = 0) {
order.clear();
order.reserve(n);
parent.assign(n, -1);
vector<int> st(1, root);
parent[root] = root;
while (!st.empty()) {
int v = st.back();
st.pop_back();
order.push_back(v);
for (int to : g[v]) {
if (to == parent[v]) continue;
parent[to] = v;
st.push_back(to);
}
}
map<vector<int>, int> ids;
for (int i = n - 1; i >= 0; --i) {
int v = order[i];
vector<int> ch;
ch.reserve(g[v].size() - (v != root));
for (int to : g[v]) {
if (to == parent[v]) continue;
ch.push_back(hash_id[to]);
}
sort(ch.begin(), ch.end());
auto [it, inserted] = ids.emplace(ch, (int)ids.size());
hash_id[v] = it->second;
}
kind_count = ids.size();
return hash_id;
}
int operator[](int v) const {
return hash_id[v];
}
int kinds() const {
return kind_count;
}
};
/**
* @brief 木ハッシュ(Tree Hash)
*/#line 1 "tree/tree_hash.cpp"
struct TreeHash {
int n;
vector<vector<int>> g;
vector<int> parent, order, hash_id;
int kind_count;
explicit TreeHash(int n)
: n(n), g(n), parent(n, -1), hash_id(n, -1), kind_count(0) {}
void add_edge(int u, int v) {
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> build(int root = 0) {
order.clear();
order.reserve(n);
parent.assign(n, -1);
vector<int> st(1, root);
parent[root] = root;
while (!st.empty()) {
int v = st.back();
st.pop_back();
order.push_back(v);
for (int to : g[v]) {
if (to == parent[v]) continue;
parent[to] = v;
st.push_back(to);
}
}
map<vector<int>, int> ids;
for (int i = n - 1; i >= 0; --i) {
int v = order[i];
vector<int> ch;
ch.reserve(g[v].size() - (v != root));
for (int to : g[v]) {
if (to == parent[v]) continue;
ch.push_back(hash_id[to]);
}
sort(ch.begin(), ch.end());
auto [it, inserted] = ids.emplace(ch, (int)ids.size());
hash_id[v] = it->second;
}
kind_count = ids.size();
return hash_id;
}
int operator[](int v) const {
return hash_id[v];
}
int kinds() const {
return kind_count;
}
};
/**
* @brief 木ハッシュ(Tree Hash)
*/