「JSOI2016」独特的树叶(树哈希)
这个题只要求出以每个点为根的有根(无标号)树的hash值就好了。
我以前的树哈希是把树转为括号序,这个太麻烦了。
一种方法是每个点的权值定义为siz,找到一个dfs序,使得经过的点的权值字典序组最小。
这个对于这道题也不方便,因为换根是可能需要前缀和后缀和搞。
在网上看到一种的hash是这个:
\(f[x]=(1+\sum_{y\in son[x]} f[y]*p[siz[y]](质数))~mod~mo\)
感觉还不错,因为是加法,所以好换根。
但是可能在树很小的时候容易错。
Code
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const ll mo = 23333333333333333;
ll mul(ll x, ll y) {
ll z = (long double) x * y / mo;
z = x * y - z * mo;
if(z < 0) z += mo; else if(z >= mo) z -= mo;
return z;
}
namespace sub1 {
const int N = 2e6 + 5;
int bz[N], p[N], p0;
void sieve(int n) {
fo(i, 2, n) {
if(!bz[i]) p[++ p0] = i;
for(int j = 1; i * p[j] <= n; j ++) {
bz[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
}
}
using sub1 :: p;
const int N = 1e5 + 5;
struct nod {
int fi[N], nt[N * 2], to[N * 2], tot, r[N];
void link(int x, int y) {
r[x] ++, r[y] ++;
nt[++ tot] = fi[x], to[tot] = y, fi[x] = tot;
nt[++ tot] = fi[y], to[tot] = x, fi[y] = tot;
}
int fa[N], siz[N];
ll f[N];
void dg(int x) {
siz[x] = 1; f[x] = 1;
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x]) {
int y = to[i];
fa[y] = x;
dg(y);
f[x] = (f[x] + mul(f[y], p[siz[y]])) % mo;
siz[x] += siz[y];
}
}
ll g[N], s[N], s2[N];
void dfs(int x) {
f[x] = 1; siz[x] = 1;
for(int i = fi[x]; i; i = nt[i]) {
int y = to[i];
f[x] = (f[x] + mul(f[y], p[siz[y]])) % mo;
siz[x] += siz[y];
}
s[x] = f[x];
s2[x] = f[to[fi[x]]];
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x]) {
int y = to[i];
g[y] = (f[x] - mul(f[y], p[siz[y]]) + mo) % mo;
}
siz[0] = siz[x];
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x]) {
int y = to[i];
f[x] = g[y];
siz[x] = siz[0] - siz[y];
dfs(y);
}
}
} e1, e2;
int n, x, y;
map<ll, int> bz;
int main() {
sub1 :: sieve(2e6);
scanf("%d", &n);
fo(i, 1, n - 1) {
scanf("%d %d", &x, &y);
e1.link(x, y);
}
fo(i, 1, n) {
scanf("%d %d", &x, &y);
e2.link(x, y);
}
e1.dg(1); e1.dfs(1);
e2.dg(1); e2.dfs(1);
fo(i, 1, n) bz[e1.s[i]] = 1;
fo(i, 1, n + 1) if(e2.r[i] == 1 && bz[e2.s2[i]]) {
pp("%d\n", i); return 0;
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址