zoukankan      html  css  js  c++  java
  • 「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;
    	}
    }
    
    
  • 相关阅读:
    Django笔记:上下文处理器和中间件
    Django笔记:Cookie和Session
    redhat 7.4从openssh7.6离线升级openssh8.4p1解决方法
    “应用程序无法正常启动(0xc000007)”处理办法
    "安装VMware Tools"显示灰色的解决办法
    redis 根据模板批量生成使用不同端口的配置文件并运行运行服务
    扩展 docker 管理命令
    shell getopt 讲解
    编写 Redis 测试 shell 脚本
    自定义 shell 软件安装脚本
  • 原文地址:https://www.cnblogs.com/coldchair/p/12720354.html
Copyright © 2011-2022 走看看