ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

JYY有两棵树A和B:树A有N个点,编号为1到N;树B有N+1个点,编号为1到N+1。JYY知道树B恰好是由树A加上一个叶
节点,然后将节点的编号打乱后得到的。他想知道,这个多余的叶子到底是树B中的哪一个叶节点呢?

Input

输入一行包含一个正整数N。
接下来N-1行,描述树A,每行包含两个整数表示树A中的一条边;
接下来N行,描述树B,每行包含两个整数表示树B中的一条边。
1≤N≤10^5

Output

输出一行一个整数,表示树B中相比树A多余的那个叶子的编号。如果有多个符合要求的叶子,输出B中编号最小的
那一个的编号

树形dp求出两棵树每个点的子树和上方子树的hash值,进而可以求出每个点作为根的整棵树(或删去一个叶子后)的hash值

有根树的hash的一个实现方式是递归定义为Hash(子树的hash值排序后的字符串hash)

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define G *++ptr
typedef long long i64;
const int N=100007,p1=1844677,p2=2939999,p=1234577;
char buf[N*40],*ptr=buf-1;
int _(){
    int x=0,c=G;
    while(c<48)c=G;
    while(c>47)x=x*10+c-48,c=G;
    return x;
}
int n,ans=0x3f3f3f3f;
struct H{
    int a,b;
    H&cal(){
        a=(a*2+b%5112+135411)%p1;
        b=(b+a%1237+212411)%p2;
        return*this;
    }
};
H operator*(H x,i64 y){return (H){x.a*y%p1,x.b*y%p2};}
H operator*(H x,H y){return (H){i64(x.a)*y.a%p1,i64(x.b)*y.b%p2};}
H operator+(H x,H y){return (H){(x.a+y.a)%p1,(x.b+y.b)%p2};}
H operator-(H x,H y){return (H){(x.a-y.a+p1)%p1,(x.b-y.b+p2)%p2};}
bool operator<(H x,H y){return x.a!=y.a?x.a<y.a:x.b<y.b;}
int cp=0,vp=0;
H*cs[N],pp[N],hs[N],vs[N];
bool cmp(H*a,H*b){return *a<*b;}
bool is(H x){return std::binary_search(vs,vs+vp,x);}
struct tree{
    int es[N*2],enx[N*2],e0[N],ep,n;
    H f1[N],f2[N];
    void init(int _n){
        ep=2;
        n=_n;
        for(int i=1,a,b;i<n;++i){
            a=_();b=_();
            es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
            es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
        }
        dfs1(1,0);
        dfs2(1,0);
    }
    void dfs1(int w,int pa){
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa)dfs1(u,w);
        }
        cp=0;
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa)cs[cp++]=f1+u;
        }
        std::sort(cs,cs+cp,cmp);
        for(int i=0;i<cp;++i)f1[w]=f1[w]*p+*cs[i];
        f1[w].cal();
    }
    void getcs(int w,int pa){
        cp=0;
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa)cs[++cp]=f1+u;
            else cs[++cp]=f2+w;
        }
        std::sort(cs+1,cs+cp+1,cmp);
    }
    void dfs2(int w,int pa){
        getcs(w,pa);
        for(int i=1;i<=cp;++i)hs[i]=hs[i-1]*p+*cs[i];
        for(int i=1;i<=cp;++i){
            if(cs[i]==f2+w)continue;
            f2[cs[i]-f1]=(hs[cp]+(hs[i-1]-hs[i])*pp[cp-i]).cal();
        }
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa)dfs2(u,w);
        }
    }
    void dfs3(int w,int pa){
        getcs(w,pa);
        for(int i=1;i<=cp;++i)hs[i]=hs[i-1]*p+*cs[i];
        for(int i=1;i<=cp;++i){
            if(cs[i]==f2+w)continue;
            int u=cs[i]-f1;
            if(!enx[e0[u]]&&u<ans&&is((hs[cp]+(hs[i-1]-hs[i])*pp[cp-i]).cal()))ans=u;
        }
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa)dfs3(u,w);
        }
    }
    void spj(){
        if(!enx[e0[1]]&&is(f1[es[e0[1]]]))puts("1"),exit(0);
    }
    void dfs4(int w,int pa){
        getcs(w,pa);
        for(int i=1;i<=cp;++i)vs[vp]=vs[vp]*p+*cs[i];
        vs[vp++].cal();
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa)dfs4(u,w);
        }
    }
}A,B;
int main(){
    fread(buf,1,sizeof(buf),stdin)[buf]=0;
    n=_();
    pp[0]=(H){1,1};
    for(int i=1;i<=n;++i)pp[i]=pp[i-1]*p;
    A.init(n);
    B.init(n+1);
    A.dfs4(1,0);
    std::sort(vs,vs+vp);
    B.spj();
    B.dfs3(1,0);
    printf("%d",ans);
    return 0;
}

 

posted on 2017-03-18 15:47  nul  阅读(849)  评论(1编辑  收藏  举报