1. 程式人生 > >BZOJ4754 JSOI2016獨特的樹葉(雜湊)

BZOJ4754 JSOI2016獨特的樹葉(雜湊)

  判斷兩棵無根樹是否同構只需要把重心提作根雜湊即可。由於只添加了一個葉子,重心的位置幾乎不發生偏移,所以直接把兩棵樹的重心提起來,逐層找雜湊值不同且對應的兩子樹即可。被一個普及組子問題卡一年。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define ul unsigned long long
#define
N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,ans,f[N],g[N]; struct tree { int p[N],t,size[N],root; ul hax[N],f[N]; struct data{int to,nxt;}edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k,int from) { size[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=from) dfs(edge[i].to,k),size[k]+=size[edge[i].to]; } int findroot(int k,int s) { int mx=0; for (int i=p[k];i;i=edge[i].nxt) if (size[edge[i].to]<size[k]&&size[edge[i].to]>size[mx]) mx=edge[i].to; if (size[mx]*2>s) return findroot(mx,s); else return k; } void refind() { for (int i=p[root];i;i=edge[i].nxt) if (size[edge[i].to]*2>=size[root]) {root=edge[i].to;break;} } void gethash(int k,int from) { for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=from) gethash(edge[i].to,k); int cnt=0; for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=from) f[++cnt]=hax[edge[i].to]; sort(f+1,f+cnt+1); hax[k]=0; for (int i=1;i<=cnt;i++) hax[k]=hax[k]*107+f[i]; hax[k]+=size[k]*509; } }a,b; bool cmp(const int&x,const int&y) { return a.hax[x]<a.hax[y]; } bool cmp2(const int&x,const int&y) { return b.hax[x]<b.hax[y]||b.hax[x]==b.hax[y]&&x>y; } void work(int x,int y) { int cnt=0,cnt2=0; for (int i=a.p[x];i;i=a.edge[i].nxt) if (a.size[a.edge[i].to]<a.size[x]) f[++cnt]=a.edge[i].to; for (int i=b.p[y];i;i=b.edge[i].nxt) if (b.size[b.edge[i].to]<b.size[y]) g[++cnt2]=b.edge[i].to; sort(f+1,f+cnt+1,cmp); sort(g+1,g+cnt2+1,cmp2); if (cnt>cnt2||cnt2>cnt+1) return; if (cnt2==cnt+1) { int t=0; for (int i=1,j=1;i<=cnt2;i++,j++) if (a.hax[f[j]]!=b.hax[g[i]]||j>cnt) if (!t) t=g[i++];else return; if (t) ans=min(ans,t); return; } if (cnt2==cnt) { int u,v; for (u=1;u<=cnt;u++) if (a.hax[f[u]]!=b.hax[g[u]]) break; if (!u) return; if (a.hax[f[u]]<b.hax[g[u]]) for (v=u;v<cnt;v++) if (a.hax[f[v+1]]!=b.hax[g[v]]) break; if (!v) return; for (int i=v+1;i<=cnt;i++) if (a.hax[f[i]]!=b.hax[g[i]]) return; for (int i=1;i<=cnt;i++) if (b.hax[g[v]]==b.hax[g[i]]) work(f[u],g[i]); } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4754.in","r",stdin); freopen("bzoj4754.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read();ans=n+1; for (int i=1;i<n;i++) { int x=read(),y=read(); a.addedge(x,y),a.addedge(y,x); } for (int i=1;i<=n;i++) { int x=read(),y=read(); b.addedge(x,y),b.addedge(y,x); } a.dfs(1,1),b.dfs(1,1); a.root=a.findroot(1,n),b.root=b.findroot(1,n+1); a.dfs(a.root,a.root),b.dfs(b.root,b.root); a.gethash(a.root,a.root),b.gethash(b.root,b.root); work(a.root,b.root); if (n&1) a.refind(); else b.refind(); a.dfs(a.root,a.root),b.dfs(b.root,b.root); a.gethash(a.root,a.root),b.gethash(b.root,b.root); work(a.root,b.root); cout<<ans; return 0; }