「JSOI2016」独特的树叶(树哈希)

https://loj.ac/problem/2072

这个题只要求出以每个点为根的有根(无标号)树的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;
	}
}

猜你喜欢

转载自www.cnblogs.com/coldchair/p/12720354.html
今日推荐