Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

树哈希模板

判断树同构。

对于无根树判断树同构,需要每个根都哈希判断。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
ULL calc (int u, int fa)
{
sz[u] = 1;
ULL res = 0;
vector <ULL> h;
for (int v : g[u]) if (v ^ fa)
h.pb(calc(v, u)), sz[u] += sz[v];
sort(h.begin(), h.end());
for (int i = 0; i < h.size(); ++i)
res += h[i] * p[i];
return res * sz[u] + 1;
}

如果是无根树,需要对于每个点作为根,可以换根DP。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
void input ()
{
read(n);
for (int i = 1; i <= n; ++i)
e[i].clear(), h[i].clear(), s[i].clear();
for (int i = 1, a; i <= n; ++i)
{
read(a);
if (a) e[a].pb(i), e[i].pb(a);
}
}
int calc (int u)
{
s[u].resize(h[u].size());
sort(h[u].begin(), h[u].end());
int res = 0;
for (int i = 0; i < h[u].size(); ++i)
{
int k = (LL)h[u][i] * pbase[i] % mod;
adj(res += k - mod);
adj((s[u][i] = k) += (i ? s[u][i - 1] : 0) - mod);
}
return (res + 1ll) * sz[u] % mod;
}
void dfs1 (int u)
{
sz[u] = 1;
for (int v : e[u]) if (v ^ p[u])
{
p[v] = u;
dfs1(v);
sz[u] += sz[v];
h[u].pb(f[v]);
}
f[u] = calc(u);
}
void dfs2 (int u)
{
g[u] = calc(u);
for (int v : e[u]) if (v ^ p[u])
{
int t = lower_bound(h[u].begin(), h[u].end(), f[v]) - h[u].begin();
sz[u] -= sz[v], sz[v] += sz[u];
int k = ((t ? s[u][t - 1] : 0) + (LL)(s[u][h[u].size() - 1] - s[u][t]) * ibase + 1) % mod * sz[u] % mod;
adj(k), h[v].pb(k);
dfs2(v);
sz[v] -= sz[u], sz[u] += sz[v];
}
}
void init () { dfs1(1), dfs2(1); }