【ZJOJ 5454】【NOIP2017提高A组冲刺11.5】仔细的检查

Description

nodgd家里种了一棵树,有一天nodgd比较无聊,就把这棵树画在了一张纸上。另一天nodgd更无聊,就又画了一张。
这时nodgd发现,两次画的顺序是不一样的,这就导致了原本的某一个节点u0在第一幅图中编号为u1,在第二副图中编号为u2。
于是,nodgd决定检查一下他画出的两棵树到底是不是一样的。nodgd已经给每棵树的节点都从1到n进行了编号,即每棵树有n个节点。
如果存在一个1到n的排列p1p2…pn,对于第一幅图中的任意一条边(u,v),在第二幅图中都能找到一条边(pu,pv),则认为这两幅图中的树是一样的。

Solution

树的哈希版子题,
(写得越猎奇越好)

Code

#include <cstdio>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,q) for(int i=A[E][q];i;i=B[E][i][0])
using namespace std;
typedef long long LL;
typedef LL Uin;
const int N=200500;
const Uin h2mo=1010003;//23 67
const Uin h1mo=4988741;//23 67
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,m,ans;
int B[4][2*N][2],A[4][N],B0[4],bv[4][N];
int Si1[N],Sz;
Uin Si[2][N];
int d[2][N];
int en;
int Ans[N],As[N];
struct qqww
{
    Uin h1,h2;
    Uin sh1,sh2;
    Uin z1,z2;
    int i,k;
}p[2][N],p1[N],p2[N];
void link(int I,int q,int w)
{ 
    bv[I][q]++;bv[I][w]++;
    B[I][++B0[I]][0]=A[I][q],A[I][q]=B0[I],B[I][B0[I]][1]=w;
    if(I<2)B[I][++B0[I]][0]=A[I][w],A[I][w]=B0[I],B[I][B0[I]][1]=q;
}
int FDz(int E,int q,int fa)
{
    Si1[q]=1;
    int mx=0;
    efo(i,q)if(B[E][i][1]!=fa)Si1[q]+=FDz(E,B[E][i][1],q),mx=max(mx,Si1[B[E][i][1]]);
    mx=max(mx,n-Si1[q]);
    if(mx<Sz)
    {
        Sz=mx;
        d[E][d[E][0]=1]=q;
    }else if(mx==Sz)d[E][++d[E][0]]=q;
    return Si1[q];
}
int dffffff(int E,int q,int fa)
{
    Si[E][q]=1;
    int mx=0;
    efo(i,q)if(B[E][i][1]!=fa)Si[E][q]+=dffffff(E,B[E][i][1],q);
    return Si[E][q];
}
Uin er1[N],er2[N];
Uin H1,H2;
void dfsf(int E,int q,int fa,int c)
{
    Uin cl=bv[E][q]-(fa!=0);
    cl=Si[E][q]*Si[E][q]*Si[E][q]*23333LL;
    p[E][q].i=q;p[E][q].k=E;
    p[E][q].sh1=p[E][q].h1=er1[c]*(Si[E][q]*Si[E][q]%h1mo*Si[E][q]*23333LL%h1mo-bv[E][q]*bv[E][q]%h1mo)%h1mo;
    p[E][q].sh2=p[E][q].h2=er2[c]*(Si[E][q]*Si[E][q]%h2mo*Si[E][q]*23333LL%h2mo-bv[E][q]*bv[E][q]%h2mo)%h2mo;
    efo(i,q)if(B[E][i][1]!=fa)
    {
        dfsf(E,B[E][i][1],q,c+1);
        p[E][q].sh1+=p[E][B[E][i][1]].sh1;
        p[E][q].sh2+=p[E][B[E][i][1]].sh2;
        if(p[E][q].sh2>=h2mo)p[E][q].sh2-=h2mo;
        if(p[E][q].sh1>=h1mo)p[E][q].sh1-=h1mo;
    }
}
void dfs(int E,int q,int fa,Uin h1,Uin h2)
{
    h2=(h2%h2mo+h2mo)%h2mo;
    h1=(h1%h1mo+h1mo)%h1mo;
    p[E][q].z1=((LL)p[E][q].h1+(LL)41LL*p[E][q].sh1%h1mo+(LL)h1*443ll%h1mo+111LL*p[E][fa].z1)%h1mo;
    p[E][q].z2=((LL)p[E][q].h2+(LL)87*p[E][q].sh2%h2mo+(LL)h2*47%h2mo+(LL)13143LL*p[E][fa].z2)%h2mo;
    H1=(H1+p[E][q].z1)%h1mo;
    H2=(H2+p[E][q].z2)%h2mo;
    h1=(h1+p[E][q].sh1)%h1mo;
    h2=(h2+p[E][q].sh2)%h2mo;
    efo(i,q)if(B[E][i][1]!=fa)
        dfs(E,B[E][i][1],q,h1-p[E][B[E][i][1]].sh1,h2-p[E][B[E][i][1]].sh2);
}
bool OK;
bool PX(qqww q,qqww w){return q.z1<w.z1||(q.z1==w.z1&&q.z2<w.z2);}
void dfsS(int q,int w,int fa)
{
    if(!OK)return;
    if(p[0][q].z1!=p[1][w].z1||p[0][q].z2!=p[1][w].z2){OK=0;return;}
    Ans[q]=w;
    int E=0;
    int t1=0;
    efo(i,q)p1[++t1]=p[0][B[0][i][1]];
    sort(p1+1,p1+1+t1,PX);
    E=1;
    int t2=0;
    efo(i,w)p2[++t2]=p[1][B[1][i][1]];
    sort(p2+1,p2+1+t2,PX);
    if(t1!=t2){OK=0;return;}
    fod(i,t1,1)link(2,q,p1[i].i);
    fod(i,t1,1)link(3,w,p2[i].i);
    for(int i=A[2][q],j=A[3][w];i;i=B[2][i][0],j=B[3][j][0])if(!Ans[B[2][i][1]])dfsS(B[2][i][1],B[3][j][1],q);
}
int main()
{
    freopen("check.in","r",stdin);
    freopen("check.out","w",stdout);
    int q,w;
    read(n);
    er1[1]=23;fo(i,2,n)er1[i]=(er1[i-1]*23LL)%h1mo;
    er2[1]=67;fo(i,2,n)er2[i]=(er2[i-1]*67LL)%h2mo;
    fo(i,1,n-1)read(q),read(w),link(0,q,w);
    fo(i,1,n-1)read(q),read(w),link(1,q,w);
    Sz=1e9;
    FDz(0,1,0);
    Sz=1e9;
    FDz(1,1,0);
    OK=0;
    fo(I,1,d[0][0])fo(J,1,d[1][0])if(bv[0][d[0][I]]==bv[1][d[1][J]])
    {
        q=d[0][I];w=d[1][J];
        dffffff(0,q,0);dffffff(1,w,0);
        dfsf(0,q,0,1); 
        H1=H2=0;dfs(0,q,0,0,0);
        Uin q1=H1,q2=H2;
        dfsf(1,w,0,1);
        H1=H2=0;dfs(1,w,0,0,0);
        if(q1!=H1||q2!=H2)continue;
        OK=1;
        dfsS(q,w,0);
        if(OK)break;
    }
    if(!OK){printf("NO\n");return 0;}
    printf("YES\n");
    fo(i,1,n)printf("%d ",Ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值