• [BZOJ4754][JSOI2016]独特的树叶


    bzoj
    luogu

    Description

    JYY有两棵树(A)(B):树(A)(N)个点,编号为(1)(N);树(B)(N+1)个节点,编号为(1)(N+1)

    JYY 知道树(B)恰好是由树(A)加上一个叶节点,然后将节点的编号打乱后得到的。他想知道,这个多余的叶子到底是树(B)中的哪一个叶节点呢?

    sol

    直接树(hash)就好了。
    但是直接(hash)不是(O(n^2))
    所以构造一个适合倒推的(hash),然后做一遍换根(dp)求以每个点为根的(hash)值。
    这里构造的(hash)函数是:

    [Hash(u)=(sum_otimes Hash(v)+base1)otimes(sz_u*base2+base3) ]

    然后做换根(dp)就好了。
    我第一遍(base)没设好(WA)(50)分。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<map>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    #define ull unsigned long long
    const int N = 2e5+5;
    const ull base1 = 1406;
    const ull base2 = 20020415;
    const ull base3 = 20011118;
    int n,to[N],nxt[N],head[N],cnt,sz[N],d[N],ans=1e9;
    ull Hash[N];map<ull,bool>M;
    void link(int u,int v){
    	to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
    }
    void dfs(int u,int f){
    	Hash[u]=0;sz[u]=1;
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=f){
    			dfs(to[e],u);
    			Hash[u]^=Hash[to[e]]+base1;
    			sz[u]+=sz[to[e]];
    		}
    	Hash[u]+=base2*sz[u]+base3;
    }
    void cal1(int u,int f){
    	M[Hash[u]]=1;
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=f){
    			ull tmp=((Hash[u]-base2*n-base3)^(Hash[to[e]]+base1))+base2*(n-sz[to[e]])+base3;
    			Hash[to[e]]=((Hash[to[e]]-base2*sz[to[e]]-base3)^(tmp+base1))+base2*n+base3;
    			cal1(to[e],u);
    		}
    }
    void cal2(int u,int f){
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=f)
    			if (d[to[e]]>1){
    			ull tmp=((Hash[u]-base2*n-base3)^(Hash[to[e]]+base1))+base2*(n-sz[to[e]])+base3;
    			Hash[to[e]]=((Hash[to[e]]-base2*sz[to[e]]-base3)^(tmp+base1))+base2*n+base3;
    			cal2(to[e],u);				
    			}else{
    				ull tmp=((Hash[u]-base2*n-base3)^(Hash[to[e]]+base1))+base2*(n-1)+base3;
    				if (M.count(tmp)) ans=min(ans,to[e]);
    			}
    }
    int main(){
    	n=gi();
    	for (int i=1;i<n;++i){
    		int u=gi(),v=gi();
    		link(u,v),link(v,u);
    	}
    	dfs(1,0);cal1(1,0);
    	memset(head,0,sizeof(head));cnt=0;++n;
    	for (int i=1;i<n;++i){
    		int u=gi(),v=gi();
    		link(u,v),link(v,u);
    		++d[u],++d[v];
    	}
    	for (int i=1;i<=n;++i)
    		if (d[i]>1){
    			dfs(i,0),cal2(i,0);
    			break;
    		}
    	printf("%d
    ",ans);return 0;
    }
    
  • 相关阅读:
    html中的块级元素、行内元素
    ptyhon_opencv 图像的基本操作
    正则表达式总结 2017.1.6
    HashMap 中的 entrySet()使用方法 2016.12.28
    (转)Redis持久化的几种方式
    负数与二进制换转方法
    (转)2019JAVA面试题附答案(长期更新)
    Java后端技术面试汇总(第一套)
    (转)Dubbo服务暴露过程源码分析
    Dubbo消费方服务调用过程源码分析
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9102235.html
Copyright © 2020-2023  润新知