听说题解里全是 (O(n^2m)) 的,今天神 @hehezhou 介绍了一种优秀的方法。
用多项式哈希,记录走过的结点的顺序。
首先如果是有根树,而且儿子结点有先后遍历顺序这样子就是对的。
然后如果儿子结点没有顺序就按照儿子的哈希值排序,然后再哈希。
有根树拓展到无根树只要找到重心然后再做即可。(两个重心也是可以的,比较的时候看看两个哈希值能否对应上即可)
于是得出了哈希值,最后暴力比较即可。
时间复杂度 (Theta(mn log n)), 时间复杂度瓶颈再于对哈希值排序。
神仙 Forever_Pursuit
说他用基数排序,因此是 (Theta(mn))。
代码:
#include<bits/stdc++.h>
#define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++)
#define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
#define ll long long
#define ull unsigned long long
#define db double
#define pii pair<int, int>
#define pil pair<int, lonf long>
#define mkp make_pair
using namespace std;
const int N = 55;
const int mod = 1019260817;
const int G = 19491001;
int Pow[N];
int n, m;
struct Tree {
int A, B;
} f[N];
bool operator == (Tree aa, Tree bb) {
return aa.A == bb.A && aa.B == bb.B;
}
int head[N], edge_id;
struct edge {
int to, next;
} e[N << 1];
void add_edge(int u, int v) {
++edge_id, e[edge_id].to = v, e[edge_id].next = head[u], head[u] = edge_id;
}
int has[N], siz[N], dep[N], rt, rrt, rtm;
void findrt(int x, int fa) {
siz[x] = 1;
int maxn = 0;
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].to;
if(v == fa) continue;
findrt(v, x), siz[x] += siz[v], maxn = max(maxn, siz[v]);
}
maxn = max(maxn, n - siz[x]);
if(maxn < rtm) rtm = maxn, rt = x, rrt = 0;
else if(maxn == rtm) rrt = x;
}
int tot;
pii sav[N];
void dfs(int x, int fa) {
has[x] = 1ll * dep[x] * Pow[1] % mod, siz[x] = 1;
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].to;
if(v == fa) continue;
dep[v] = dep[x] + 1, dfs(v, x);
}
tot = 0;
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].to;
if(v == fa) continue;
sav[++tot] = mkp(has[v], siz[v]);
}
sort(sav + 1, sav + tot + 1);
L(i, 1, tot) (has[x] += 1ll * sav[i].first * Pow[siz[x]] % mod) %= mod, siz[x] += sav[i].second;
}
void In(int x) {
rtm = mod, rrt = 0;
scanf("%d", &n);
L(i, 1, n) {
int v; scanf("%d", &v);
if(v) add_edge(i, v), add_edge(v, i);
}
findrt(1, -1);
dep[rt] = 1, dfs(rt, -1), f[x].A = has[rt];
if(rrt) dep[rrt] = 1, dfs(rrt, -1), f[x].B = has[rrt];
if(f[x].A < f[x].B) swap(f[x].A, f[x].B);
L(i, 1, n) head[i] = 0;
edge_id = 0;
}
int mian() {
Pow[0] = 1;
L(i, 1, 50) Pow[i] = 1ll * Pow[i - 1] * G % mod;
scanf("%d", &m);
L(i, 1, m) In(i);
L(i, 1, m) L(j, 1, i) if(f[i] == f[j]) {
printf("%d
", j);
break;
}
return 0;
}
祝大家学习愉快!