题目描述

nodgd家里种了一棵树,有一天nodgd比较无聊,就把这棵树画在了一张纸上。另一天nodgd更无聊,就又画了一张。
  这时nodgd发现,两次画的顺序是不一样的,这就导致了原本的某一个节点u0在第一幅图中编号为u1,在第二副图中编号为u2。
  于是,nodgd决定检查一下他画出的两棵树到底是不是一样的。nodgd已经给每棵树的节点都从1到n进行了编号,即每棵树有n个节点。
  如果存在一个1到n的排列p1,p2…pn,对于第一幅图中的任意一条边(i,j),在第二幅图中都能找到一条边(pi,pj),则认为这两幅图中的树是一样的。

输入格式

第一行一个整数n,表示节点的总数。
  接下来n−1行,每行两个整数,表示第一幅图中的每一条边。
  接下来n−1行,每行两个整数,表示第二幅图中的每一条边。

输出格式

如果两幅图的树是一样的,第一行输出”YES”,接下来1行输出一个1到n的排列p1,p2,……,pn,两个数之间用空格间隔。当多个排列都满足题意时,你可以随便输出一个。
  如果两幅图的树是不一样的,只输出一行”NO”。
  注意输出的时候不要加引号。

输入样例

3
  1 2
  2 3
  1 3
  3 2

输出样例

YES
  1 3 2
  提示
【样例解释1】
  肉眼可见,1-2-3和1-3-2显然是一样的两棵树。不过这可能不是唯一的符合题意的排列。
  数据范围:n<=100000

分析

正解好像是什么括号序列,被机房的大佬用树hash强行卡过了。。。。。。

对于一棵树,什么东西与它的根节点无关呢?

反正我知道的只有重心与直径

所以把重心找出来,直接树hash,再从根节点往下一一对应,判断子节点的对应点时用hash值给子节点排个序就好了

注意不能直接根据每个节点的hash值排序对应,因为如果有两棵子树结构相同,祖先子树结构不同时它们是无法被区分的。

好像这是我第一次写树的重心

另外此题hash也有技巧,有一篇论文《Hash在信息学竞赛中的一类应用》(反正我没看,只是用了他的hash方法)

代码

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=;
const unsigned long long seed=;
int n,cnt[],ans[maxn];
unsigned long long ha[][maxn];
vector<int>g[],son[][maxn];
int info[][maxn],nx[][maxn<<],v[][maxn<<];
void add(int u1,int v1,int k){nx[k][++cnt[k]]=info[k][u1];info[k][u1]=cnt[k];v[k][cnt[k]]=v1;}
bool cmp0(int a,int b){return ha[][a]<ha[][b];}bool cmp1(int a,int b){return ha[][a]<ha[][b];}
int yousa(int x,int f,int k)
{
int sz=,flag=;
for(int i=info[k][x],del;i;i=nx[k][i])if(v[k][i]!=f)
sz+=(del=yousa(v[k][i],x,k)),flag&=((del<<)<=n);
flag&=(((n-sz)<<)<=n);if(flag)g[k].push_back(x);
return sz;
}
void VR(int x,int f,int k)
{
son[k][x].clear();
for(int i=info[k][x];i;i=nx[k][i])
{
if(v[k][i]!=f)
VR(v[k][i],x,k),son[k][x].push_back(v[k][i]);
}
if(k==)sort(son[k][x].begin(),son[k][x].end(),cmp0);
if(k==)sort(son[k][x].begin(),son[k][x].end(),cmp1);
ha[k][x]=;
for(int i=son[k][x].size()-;i>=;i--)ha[k][x]=ha[k][x]*seed^ha[k][son[k][x][i]];
ha[k][x]*=seed*seed;
}
void solve(int a,int b){ans[a]=b;for(int i=son[][a].size()-;i>=;i--)solve(son[][a][i],son[][b][i]);}
int main()
{
scanf("%d",&n);
for(int k=;k<=;k++)for(int i=,u1,v1;i<n;i++)
scanf("%d%d",&u1,&v1),add(u1,v1,k),add(v1,u1,k);
yousa(,,);yousa(,,);
for(int i=,lim=g[].size();i<lim;i++)
{
VR(g[][i],,);
for(int j=,lim=g[].size();j<lim;j++)
{
VR(g[][j],,);
if(ha[][g[][i]]==ha[][g[][j]])
{
puts("YES");solve(g[][i],g[][j]);
for(int k=;k<=n;k++)printf("%d%c",ans[k],k==n?'\n':' ');
return ;
}
}
}
puts("NO");
}
05-11 22:51