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


    https://loj.ac/problem/2072

    这个题只要求出以每个点为根的有根(无标号)树的hash值就好了。

    我以前的树哈希是把树转为括号序,这个太麻烦了。

    一种方法是每个点的权值定义为siz,找到一个dfs序,使得经过的点的权值字典序组最小。

    这个对于这道题也不方便,因为换根是可能需要前缀和后缀和搞。

    在网上看到一种的hash是这个:
    (f[x]=(1+sum_{yin 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("
    ")
    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
    ", i); return 0;
    	}
    }
    
    
  • 相关阅读:
    程序员常用英语词汇
    声明式编程与命令式编程
    vue 常用ui组件库
    Vue 组件之间传值
    vscode插件之背景插件(background)
    iconfont的使用
    CSS3 @font-face 规则
    CSS抗锯齿 font-smoothing 属性介绍
    new Image 读取宽高为0——onload
    js的for循环中出现异步函数,回调引用的循环值始终是最后的值
  • 原文地址:https://www.cnblogs.com/coldchair/p/12720354.html
Copyright © 2020-2023  润新知