luogu4323 独特的树叶

题目描述

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 中编号最小的那一个的编号。

输入输出样例

输入

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

输出

1

说明/提示

对于所有数据,\(1 \leq n \leq 10 ^ 5\)


求出A树中所有点为根的树哈希值,并排序!
求出B树中所有点为根的树哈希值,从小到大枚举每一个叶子,如果它连接的点的哈希值减去这个叶子对它的贡献(为2)可以在A树所有哈希值中找到则输出,并结束程序!


#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct edge
{
	int u,v,nxt;
}e[maxn<<1],ee[maxn<<1];
int head[maxn],js,headd[maxn],jss;
void addage(int u,int v)
{
	e[++js].u=u;e[js].v=v;
	e[js].nxt=head[u];head[u]=js;
}
void addagee(int u,int v)
{
	ee[++jss].u=u;ee[jss].v=v;
	ee[jss].nxt=headd[u];headd[u]=jss;
}
int n;
bool noprime[(int)2e6+10];
int prime[maxn],cnt;
void getprime()
{
	for(int i=2;i<2e6+10;++i)
	{
		if(cnt>n)return;
		if(!noprime[i])prime[++cnt]=i;
		for(int j=1;j<=cnt;++j)
		{
			if(i*prime[j]>2e6)break;
			noprime[i*prime[j]]=1;
			if(i%prime[j]==0)break;
		}
	}	
}
int f[maxn],siz[maxn],g[maxn];
void dfs(int u,int fa)
{
	f[u]=siz[u]=1;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);
		siz[u]+=siz[v];
		f[u]+=f[v]*prime[siz[v]];
	}
}
void getg(int u,int fa,int faf)
{
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		if(v==fa)continue;
		int tp=f[u]-f[v]*prime[siz[v]]+faf*prime[n-siz[u]];
		g[v]=f[v]+tp*prime[n-siz[v]];
		getg(v,u,tp);
	}
}
int ff[maxn],sizz[maxn],gg[maxn];
void dfss(int u,int fa)
{
	ff[u]=sizz[u]=1;
	for(int i=headd[u];i;i=ee[i].nxt)
	{
		int v=ee[i].v;
		if(v==fa)continue;
		dfss(v,u);
		sizz[u]+=sizz[v];
		ff[u]+=ff[v]*prime[sizz[v]];
	}
}
void getgg(int u,int fa,int faf)
{
	for(int i=headd[u];i;i=ee[i].nxt)
	{
		int v=ee[i].v;
		if(v==fa)continue;
		int tp=ff[u]-ff[v]*prime[sizz[v]]+faf*prime[n+1-sizz[u]];
		gg[v]=ff[v]+tp*prime[n+1-sizz[v]];
		getgg(v,u,tp);
	}
}
int du[maxn],mnd[maxn];
int main()
{
	scanf("%d",&n);
	getprime();
	for(int u,v,i=1;i<n;++i)
	{
		scanf("%d%d",&u,&v);
		addage(u,v);addage(v,u);
	}
	for(int u,v,i=1;i<=n;++i)
	{
		scanf("%d%d",&u,&v);
		addagee(u,v);addagee(v,u);
		++du[u];++du[v];
	}
	dfs(1,0);
	g[1]=f[1];
	getg(1,0,0);
	sort(g+1,g+1+n);
	dfss(1,0);
	gg[1]=ff[1];
	getgg(1,0,0);
	for(int u=1;u<n+1;++u)
	{
		if(du[u]!=1)continue;
		int i=headd[u];
		int w=gg[ee[i].v]-2;
		int tp=lower_bound(g+1,g+1+n,w)-g;
		if(tp>n)continue;
		if(g[tp]==w)
		{
			printf("%d",u);
			return 0;
		}
	}
	return 0;
}
上一篇:图(Prime算法、 Kruskal算法、Dijkstra算法、Floyd算法、AOV网)


下一篇:欧拉筛与素数判定