@ysner
2018-06-08T14:31:13.000000Z
字数 3318
阅读 2428
树哈希
给出各种形态的树,问哪些树互为重构树?
一开始没注意到不论树有没有根,都要以树的重心为根,根的不同可以改变树的形态,如一棵树变成一条链之类。
树的重心的要求是使子树 最大规模 最小
显然使用树哈希。
#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<cstdlib>#include<algorithm>#define ll long long#define re register#define il inline#define fp(i,a,b) for(re int i=a;i<=b;i++)#define fq(i,a,b) for(re int i=a;i>=b;i--)using namespace std;const int N=105,mod1=498353,mod2=412817,mod=1<<30;int n,h[N],cnt,m,B1=3,B2=7,B3=11,sz[N],vis1[500000],vis2[500000],dp[N],root;ll Hash[N];struct Edge{int to,next;}e[N<<1];il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}il void dfs(re int u,re int fa,re int deep){//printf("%d %d %d\n",u,fa,deep);re ll sum=0;sz[u]=1;for(re int i=h[u];i+1;i=e[i].next){re int v=e[i].to;if(v==fa) continue;dfs(v,u,deep+1);//printf("%d\n",Hash[v]);sum^=Hash[v];sz[u]+=sz[v];}Hash[u]^=((sum+B1)*(sz[u]+B2)*(deep+B3));Hash[u]%=mod;//printf("%lld %d\n",Hash[u],u);}il void getroot(re int u,re int fa){sz[u]=1;for(re int i=h[u];i+1;i=e[i].next){re int v=e[i].to;if(v==fa) continue;getroot(v,u);sz[u]+=sz[v];dp[u]=max(dp[u],sz[v]);}dp[u]=max(dp[u],n-dp[u]);if(dp[u]<dp[root]) root=u;else if(dp[u]==dp[root]&&u<root) root=u;}int main(){m=gi();fp(o,1,m){memset(h,-1,sizeof(h));cnt=0;memset(Hash,0,sizeof(Hash));memset(dp,0,sizeof(dp));dp[0]=1e9;memset(sz,0,sizeof(sz));n=gi();root=0;fp(i,1,n){re int v=gi();if(v) add(i,v),add(v,i);}getroot(1,0);//printf("%d %d\n",o,root);dfs(root,0,1);//printf("%d %lld\n",o,Hash[1]);if(vis1[Hash[root]%mod1]&&vis2[Hash[root]%mod2]) printf("%d\n",vis1[Hash[root]%mod1]);else printf("%d\n",vis1[Hash[root]%mod1]=vis2[Hash[root]%mod2]=o);}return 0;}
在对进行排序后,
哈希方程变为这样(为当前节点,为子节点,为质数表)
#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<cstdlib>#include<algorithm>#define ll long long#define re register#define il inline#define fp(i,a,b) for(re int i=a;i<=b;i++)#define fq(i,a,b) for(re int i=a;i>=b;i--)using namespace std;const int N=105;int n,h[N],cnt,m,p[55];ll Hash[N][N],dp[N];struct Edge{int to,next;}e[N<<1];il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}il ll gi(){re ll x=0,t=1;re char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();if(ch=='-') t=-1,ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();return x*t;}il void wri(re int x){if(x<0) putchar('-'),x=-x;if(x>9) wri(x/10);putchar(x%10+'0');}il void dfs(re int u,re int fa){re ll top=0,s[55];s[++top]=1;for(re int i=h[u];i+1;i=e[i].next){re int v=e[i].to;if(v==fa) continue;dfs(v,u);s[++top]=dp[v];}dp[u]=0;sort(s+1,s+1+top);fp(i,1,top) dp[u]+=s[i]*p[i];}il void Pre(){re int tot=0;fp(i,41,300){re int flag=1;fp(j,2,sqrt(i)) if(i%j==0) {flag=0;break;}if(flag) p[++tot]=i;if(tot>50) break;}}int main(){Pre();m=gi();fp(o,1,m){memset(h,-1,sizeof(h));cnt=0;memset(dp,0,sizeof(dp));n=gi();fp(i,1,n){re int v=gi();if(v) add(i,v),add(v,i);}fp(i,1,n) dfs(i,0),Hash[o][i]=dp[i];sort(Hash[o]+1,Hash[o]+1+n);//fp(i,1,n) printf("%lld ",Hash[o][i]);puts("");fp(i,1,o){re int flag=1;fp(j,1,n) if(Hash[o][j]!=Hash[i][j]){//printf("%d %d %lld\n",i,j,Hash[i][j]);flag=0;break;}if(flag) {printf("%d\n",i);break;}}}return 0;}
