【NOIP2017提高组】仔细的检查

5 篇文章 0 订阅

Description

这里写图片描述

Solution

把编号抛开来看就是判断两棵树是否同构,之后再随便搞搞把编号对应上去。
判断树的同构用树哈希就好了,把每个节点的信息处理成哈希值,只要两棵树是同构的,以两棵树的重心为根的树只要保证同样形态的儿子节点是按顺序来枚举的,求哈希的时候就可以随便乱搞。判断了树同构之后在两棵树上同时BFS就能够对应出一个P数组。
因为只用一个质数可能会被卡,可以在加入的值中再乘上另一个质数就能够减少出错概率。

Code

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<stdio.h>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,x) for(i=la[x];i;i=ne[i])
#define REP(i,x) for(i=LA[x];i;i=NE[i])
#define root {if(!rt1)rt1=x;else rt2=x;}
#define ROOT {if(!RT1)RT1=x;else RT2=x;}
typedef unsigned long long ull;
const int N=1e5+5;
const ull P=63,Q=31;
struct arr{ull s;int x;}d[N],D[N];
ull S[N],tot[N],TOT[N];
int la[N],da[N*2],ne[N*2],sum,rt1,rt2,node[N],dl[N];
int LA[N],DA[N*2],NE[N*2],SUM,RT1,RT2,NODE[N],DL[N];
int n,i,x,y,ans[N],ns,NS;
bool cmp(arr x,arr y){return x.s<y.s;}
void ins(int x,int y){da[++sum]=y;ne[sum]=la[x];la[x]=sum;}
void INS(int x,int y){DA[++SUM]=y;NE[SUM]=LA[x];LA[x]=SUM;}
void gnode(int x,int fa){
    int i,mx=0;node[x]=1;
    rep(i,x)if(da[i]!=fa)
        gnode(da[i],x),mx=max(mx,node[da[i]]),node[x]+=node[da[i]];
    if((n-node[x]<=n/2)&&(mx<=n/2)) root;
}
void Gnode(int x,int fa){
    int i,mx=0;NODE[x]=1;
    REP(i,x)if(DA[i]!=fa)
        Gnode(DA[i],x),mx=max(mx,NODE[DA[i]]),NODE[x]+=NODE[DA[i]];
    if((n-NODE[x]<=n/2)&&(mx<=n/2)) ROOT;
}
void fill(int x,int fa){
    int i;node[x]=1;
    rep(i,x)if(da[i]!=fa) fill(da[i],x),node[x]+=node[da[i]];
    ns=0;rep(i,x)if(da[i]!=fa) S[++ns]=tot[da[i]];
    tot[x]=tot[x]*P+node[x]*Q;
    if(!ns) return;sort(S+1,S+ns+1);
    fo(i,1,ns) tot[x]=tot[x]*P+S[i]*Q;
}
void FILL(int x,int fa){
    int i;NODE[x]=1;
    REP(i,x)if(DA[i]!=fa) FILL(DA[i],x),NODE[x]+=NODE[DA[i]];
    NS=0;REP(i,x)if(DA[i]!=fa) S[++NS]=TOT[DA[i]];
    TOT[x]=TOT[x]*P+NODE[x]*Q;
    if(!NS) return;sort(S+1,S+NS+1);
    fo(i,1,NS) TOT[x]=TOT[x]*P+S[i]*Q;
}
void bfs(int rt,int fa,int RT,int FA){
    int i,l=0,r=1;
    dl[1]=rt;DL[1]=RT;
    while(l<r){
        l++;rt=dl[l];RT=DL[l];ans[rt]=RT;
        ns=0;rep(i,rt)if(node[da[i]]<node[rt])d[++ns]=(arr){tot[da[i]],da[i]};
        NS=0;REP(i,RT)if(NODE[DA[i]]<NODE[RT])D[++NS]=(arr){TOT[DA[i]],DA[i]};
        sort(d+1,d+ns+1,cmp);sort(D+1,D+NS+1,cmp);
        fo(i,1,ns) r++,dl[r]=d[i].x,DL[r]=D[i].x;
    }
}
bool pd(int rt,int RT){
    memset(node,0,sizeof(node));
    memset(tot,0,sizeof(tot));fill(rt,0);
    memset(NODE,0,sizeof(NODE));
    memset(TOT,0,sizeof(TOT));FILL(RT,0);
    if(tot[rt]!=TOT[RT]) return 0;
    bfs(rt,0,RT,0);return 1;
}
int main(){
    scanf("%d",&n);
    fo(i,1,n-1) scanf("%d%d",&x,&y),ins(x,y),ins(y,x);
    fo(i,1,n-1) scanf("%d%d",&x,&y),INS(x,y),INS(y,x);
    gnode(1,0);Gnode(1,0);
    if(pd(rt1,RT1)||pd(rt1,RT2)||pd(rt2,RT1)||pd(rt2,RT2)){
        if(ans[1]==0){
            printf("NO\n");return 0;
        }
        printf("YES\n");
        fo(i,1,n) printf("%d ",ans[i]);printf("\n");
        return 0;
    }
    printf("NO\n");
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值