【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"); }
相關文章
相關標籤/搜索