【CSP模拟赛】仔细的检查(树的重心&树hash)

题目描述

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

输入格式

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

输出格式

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

输入样例

  3
  1 2
  2 3
  1 3
  3 2排序

输出样例

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

分析it

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

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

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

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

  注意不能直接根据每一个节点的hash值排序对应,由于若是有两棵子树结构相同,祖先子树结构不一样时它们是没法被区分的。

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

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

  代码

#include<cstdio> #include<vector> #include<algorithm> using namespace std; const int maxn=100005; const unsigned long long seed=998244353; int n,cnt[2],ans[maxn]; unsigned long long ha[2][maxn]; vector<int>g[2],son[2][maxn]; int info[2][maxn],nx[2][maxn<<1],v[2][maxn<<1]; 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[0][a]<ha[0][b];}bool cmp1(int a,int b){return ha[1][a]<ha[1][b];} int yousa(int x,int f,int k) { int sz=1,flag=1; 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<<1)<=n); flag&=(((n-sz)<<1)<=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==0)sort(son[k][x].begin(),son[k][x].end(),cmp0); if(k==1)sort(son[k][x].begin(),son[k][x].end(),cmp1); ha[k][x]=1; for(int i=son[k][x].size()-1;i>=0;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[0][a].size()-1;i>=0;i--)solve(son[0][a][i],son[1][b][i]);} int main() { scanf("%d",&n); for(int k=0;k<=1;k++)for(int i=1,u1,v1;i<n;i++) scanf("%d%d",&u1,&v1),add(u1,v1,k),add(v1,u1,k); yousa(1,0,0);yousa(1,0,1); for(int i=0,lim=g[0].size();i<lim;i++) { VR(g[0][i],0,0); for(int j=0,lim=g[1].size();j<lim;j++) { VR(g[1][j],0,1); if(ha[0][g[0][i]]==ha[1][g[1][j]]) { puts("YES");solve(g[0][i],g[1][j]); for(int k=1;k<=n;k++)printf("%d%c",ans[k],k==n?'\n':' '); return 0; } } } puts("NO"); }
相关文章
相关标签/搜索