• JSOI2016 独特的树叶


    JSOI 2016 独特的树叶

    题面描述

    有两颗大小分别为(n)(n+1)的树,问删除后者的一个叶子,两者能否同构。如果能,输出最小的叶子标号使得删去这个叶子两者同构。

    数据范围:(nle 10^5)

    思路

    用一些玄学方法把第一棵树每个点及其子树(hash)起来,再(up-down)一下,求出每个点作为根这整棵树的(hash)值,存入(map)中。

    再用类似的方法操作第二棵树即可。

    关于树哈希的方法,建议使用异或,这样不仅撤销方便,而且无视顺序,无需排序。

    代码

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mkp(x,y) make_pair(x,y)
    #define go(x) for(int i=head[x];i;i=edge[i].nxt)
    #define now edge[i].v
    using namespace std;
    const int sz=1e5+7;
    const int p1=1e8+7;
    const int p2=998244353;
    const int q1=52437;
    const int q2=9813475;
    int n;
    int ans;
    int u,v,cnt;
    int r[sz];
    int siz[sz];
    int head[sz];
    int w[sz][2];
    int hs[sz][2];
    map<pii,int>mp;
    struct Edge{
    	int v,nxt;
    }edge[sz<<1];
    void make_edge(int u,int v){
    	edge[++cnt]=(Edge){v,head[u]};head[u]=cnt;
    	edge[++cnt]=(Edge){u,head[v]};head[v]=cnt; 
    }
    void dfs(int x,int fa){
    	siz[x]=1;
    	go(x) if(now!=fa){
    		dfs(now,x);
    		siz[x]+=siz[now];
    		hs[x][0]^=1ll*w[siz[now]][0]*hs[now][0]%p1;
    		hs[x][1]^=1ll*w[siz[now]][1]*hs[now][1]%p2;
    	}
    	hs[x][0]^=siz[x];
    	hs[x][1]^=siz[x];
    }
    void Dfs(int x,int fa,int n0,int n1){
    	mp[mkp(n0,n1)]=1;
    	int k0,k1,t0,t1;
    	go(x) if(now!=fa){
    		k0=n0^n^(n-siz[now])^(1ll*w[siz[now]][0]*hs[now][0]%p1);
    		k1=n1^n^(n-siz[now])^(1ll*w[siz[now]][1]*hs[now][1]%p2);
    		t0=hs[now][0]^siz[now]^n^(1ll*w[n-siz[now]][0]*k0%p1);
    		t1=hs[now][1]^siz[now]^n^(1ll*w[n-siz[now]][1]*k1%p2);
    		Dfs(now,x,t0,t1);
    	}
    }
    void getans(int x,int fa,int n0,int n1){
    	int k0,k1,t0,t1;
    	go(x) if(now!=fa){
    		if(siz[now]==1){
    			t0=n0^n^(n-1)^(1ll*w[siz[now]][0]*hs[now][0]%p1);
    			t1=n1^n^(n-1)^(1ll*w[siz[now]][1]*hs[now][1]%p2);
    			if(mp.find(mkp(t0,t1))!=mp.end()) ans=min(ans,now);
    			continue;
    		}
    		k0=n0^n^(n-siz[now])^(1ll*w[siz[now]][0]*hs[now][0]%p1);
    		k1=n1^n^(n-siz[now])^(1ll*w[siz[now]][1]*hs[now][1]%p2);
    		t0=hs[now][0]^siz[now]^n^(1ll*w[n-siz[now]][0]*k0%p1);
    		t1=hs[now][1]^siz[now]^n^(1ll*w[n-siz[now]][1]*k1%p2);
    		getans(now,x,t0,t1);
    	}
    }
    int main(){
    	scanf("%d",&n);
    	w[0][0]=w[0][1]=1;
    	for(int i=1;i<=n+1;i++){
    		w[i][0]=1ll*w[i-1][0]*q1%p1;
    		w[i][1]=1ll*w[i-1][1]*q2%p2;
    	}
    	for(int i=1;i<n;i++){
    		scanf("%d%d",&u,&v);
    		make_edge(u,v);
    	}
    	dfs(1,0);
    	Dfs(1,0,hs[1][0],hs[1][1]);
    	n++;
    	cnt=0;
    	ans=INT_MAX;
    	memset(head,0,sizeof(head));
    	memset(hs,0,sizeof(hs));
    	for(int i=1;i<n;i++){
    		scanf("%d%d",&u,&v);
    		r[u]++,r[v]++;
    		make_edge(u,v);
    	}
    	dfs(1,0);
    	getans(1,0,hs[1][0],hs[1][1]);
    	if(r[1]==1){
    		int v=edge[head[1]].v;
    		if(mp.find(mkp(hs[v][0],hs[v][1]))!=mp.end()) ans=min(ans,1);
    	}
    	if(ans!=INT_MAX) printf("%d
    ",ans);
    	else puts("-1");
    }
    
  • 相关阅读:
    非系统表空间损坏,rman备份恢复
    非系统数据文件损坏,rman备份恢复
    开启 控制文件自动备份下,参数文件、控制文件全部丢失恢复
    rman命令详解(三)
    Block Change Tracking (块改变跟踪)
    如何加快建 index 索引 的时间
    RMAN兼容性、控制文件自动备份、保存时间、备份策略、备份脚本(二)
    rman理论(一)
    动态参数与静态参数的判断、修改
    闪回之 Flashback Data Archive
  • 原文地址:https://www.cnblogs.com/river-flows-in-you/p/11990034.html
Copyright © 2020-2023  润新知