列表

详情


NC20230. [JSOI2016]独特的树叶

描述

JYY有两棵树A和B:树A有N个点,编号为1到N;树B有N+1个点,编号为1到N+1。
JYY知道树B恰好是由树A加上一个叶 节点,然后将节点的编号打乱后得到的。
他想知道,这个多余的叶子到底是树B中的哪一个叶节点呢?

输入描述

输入一行包含一个正整数N。
接下来N-1行,描述树A,每行包含两个整数表示树A中的一条边;
接下来N行,描述树B,每行包含两个整数表示树B中的一条边。

输出描述

输出一行一个整数,表示树B中相比树A多余的那个叶子的编号。
如果有多个符合要求的叶子,输出B中编号最小的那一个的编号

示例1

输入:

5
1 2
2 3
1 4
1 5
1 2
2 3
3 4
4 5
3 6

输出:

1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 175ms, 内存消耗: 22212K, 提交时间: 2023-05-23 21:13:03

#include <iostream>
#include <cstdio>
#include <set>
#include <vector>
using namespace std;
const int maxn=100005;
const unsigned long long seed_one=998244353;
const unsigned long long seed_two=100000007;
struct Hash
{
	unsigned long long P,Q;
	void operator = (const Hash & B)
	{
		P=B.P;Q=B.Q;
	}
	Hash operator ^ (const Hash & B) const
	{
		Hash A;
		A.P=P^B.P;	A.Q=Q^B.Q;
		return A;
	}
	Hash operator * (const unsigned long long & B) const
	{
		Hash A;
		A.P=P*B;	A.Q=Q*B;
		return A;
	}
	Hash operator + (const unsigned long long & B) const
	{
		Hash A;
		A.P=P+B;	A.Q=Q+B;
		return A;
	}
	Hash operator - (const unsigned long long & B) const
	{
		Hash A;
		A.P=P-B;	A.Q=Q-B;
		return A;
	}
	bool operator < (const Hash & B) const
	{
		return P<B.P || P==B.P && Q<B.Q;
	}
	Hash complicated(int S) const
	{
		Hash O;
		O.P=P*seed_one+S;
		O.Q=Q*seed_two+S;
		return O;
	}
}fA[maxn],fB[maxn],temp,Hash_rootA[maxn],Hash_rootB[maxn];
vector<int> A[maxn],B[maxn];
int n,x,y,sizeA[maxn],sizeB[maxn];
set <Hash> S;
void dfsA(int u,int father)
{
	sizeA[u]=1;
	for (int i=0,N=A[u].size();i<N;++i)
	{
		int v=A[u][i];
		if (v==father)	continue;
		dfsA(v,u);
		fA[u]=((fA[u])^(fA[v].complicated(sizeA[v])));
		sizeA[u]+=sizeA[v];
	}
	fA[u]=fA[u]+233*sizeA[u]+1;
}
void re_dfsA(int u,int father)
{
	if (father==0)	Hash_rootA[u]=fA[u];
	else
	{
		temp=((Hash_rootA[father]-233*n-1)^fA[u].complicated(sizeA[u]));
		temp=(temp+233*(n-sizeA[u])+1);
		Hash_rootA[u]=((fA[u]-233*sizeA[u]-1)^temp.complicated(n-sizeA[u]));
		Hash_rootA[u]=Hash_rootA[u]+233*n+1;
	}
	for (int i=0,N=A[u].size();i<N;++i)
	{
		int v=A[u][i];
		if (v==father)	continue;
		re_dfsA(v,u);
	}
}
void dfsB(int u,int father)
{
	sizeB[u]=1;
	for (int i=0,N=B[u].size();i<N;++i)
	{
		int v=B[u][i];
		if (v==father)	continue;
		dfsB(v,u);
		fB[u]=(fB[u]^(fB[v].complicated(sizeB[v])));
		sizeB[u]+=sizeB[v];
	}
	fB[u]=fB[u]+233*sizeB[u]+1;
}
void re_dfsB(int u,int father)
{
	if (father==0)	Hash_rootB[u]=fB[u];
	else
	{
		temp=(Hash_rootB[father]-233*(n+1)-1)^fB[u].complicated(sizeB[u]);
		temp=(temp+233*(n+1-sizeB[u])+1);
		Hash_rootB[u]=((fB[u]-233*sizeB[u]-1)^temp.complicated(n+1-sizeB[u]));
		Hash_rootB[u]=Hash_rootB[u]+233*(n+1)+1;
	}
	for (int i=0,N=B[u].size();i<N;++i)
	{
		int v=B[u][i];
		if (v==father)	continue;
		re_dfsB(v,u);
	}
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<n;++i)
	{
		scanf("%d%d",&x,&y);
		A[x].push_back(y);
		A[y].push_back(x);
	}
	for (int i=1;i<=n;++i)
	{
		scanf("%d%d",&x,&y);
		B[x].push_back(y);
		B[y].push_back(x);
	}
	dfsA(1,0);
	re_dfsA(1,0);
	dfsB(1,0);
	re_dfsB(1,0);
	for (int i=1;i<=n;++i)
		S.insert(Hash_rootA[i]);
	//for (int i=1;i<=n+1;++i)	cout<<i<<' '<<Hash_rootA[i].P<<' '<<Hash_rootA[i].Q<<' '<<Hash_rootB[i].P<<' '<<Hash_rootB[i].Q<<endl;
	for (int i=1;i<=n+1;++i)
		if (B[i].size()==1)
		{
			Hash T;
			T.P=T.Q=234;
			Hash temp=((Hash_rootB[B[i][0]]-233*(n+1)-1)^T.complicated(1));
			temp=(temp+233*n+1);
		//	cout<<i<<' '<<temp.P<<' '<<temp.Q<<endl;
			if (S.find(temp)!=S.end())
			{
				printf("%d\n",i);
				break;
			}
		}
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 83ms, 内存消耗: 12644K, 提交时间: 2020-03-26 20:18:28

#include<iostream>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;

#define LL long long
#define ULL unsigned long long
#define fgx cerr<<"------------------"<<endl;
#define dgx cerr<<"=================="<<endl;
#define prt(x) cerr<<#x<<": "<<x<<endl;

inline int read(){
	int x=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*f;
}
const int MAXN = 100010; //H[j]*Seed+Sz[j]
const ULL Base = 1000000007;

int N; map<ULL,bool> mp;

struct tree{
	int Node[MAXN<<1],Next[MAXN<<1],Root[MAXN]; int cnte;
	int Deg[MAXN],sz[MAXN]; int opN; ULL f[MAXN],g[MAXN];;
	
	inline ULL Data(ULL x,ULL y){ return x*Base+y; }
	inline void insert(int x,int y){
		Node[++cnte]=y; Next[cnte]=Root[x]; Root[x]=cnte;
		Node[++cnte]=x; Next[cnte]=Root[y]; Root[y]=cnte;
		++Deg[x]; ++Deg[y];
	} inline void dfs1(int x,int Fa){
		sz[x]=1; g[x]=1;
		for(int i=Root[x];i;i=Next[i]){
			int y=Node[i];
			if(y!=Fa){
				dfs1(y,x); sz[x]+=sz[y]; g[x]^=Data(g[y],sz[y]);
			}
		}
	} inline void dfs2(int x,int Fa){
		if(!Fa)f[x]=g[x]; else f[x]=g[x]^Data(f[Fa]^Data(g[x],sz[x]),opN-sz[x]);
		for(int i=Root[x];i;i=Next[i]){ int y=Node[i]; if(y!=Fa) dfs2(y,x); }
	} inline bool isLev(int x){ return Deg[x]==1; }
	inline ULL Nowk(int x){
		int Fa=Node[Root[x]];
		return f[Fa]^Data(g[x],1);
	}
}A,B;

int main(){
	N=read(); A.opN=N; B.opN=N+1;
	for(int i=1;i<N;i++){
		int x=read(),y=read();
		A.insert(x,y);
	} A.dfs1(1,0); A.dfs2(1,0);
	for(int i=1;i<=N;i++) mp[A.f[i]]=true;
	for(int i=1;i<=N;i++){
		int x=read(),y=read();
		B.insert(x,y);
	} for(int i=1;i<=N+1;i++)
		if(!B.isLev(i)){
			B.dfs1(i,0); B.dfs2(i,0); break;
		}
	for(int i=1;i<=N+1;i++)
		if(B.isLev(i)){
			ULL now=B.Nowk(i);
			if(mp[now]){
				printf("%d\n",i); return 0;
			}
		}
	return 0;
}

上一题