zoukankan      html  css  js  c++  java
  • bzoj4754: [Jsoi2016]独特的树叶

    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;
    }
  • 相关阅读:
    如何修炼成某一领域的高手?
    宝宝为什么见生人就哭
    绩效管理
    《管理3.0》读书笔记
    卡特尔16PF性格测试与答案
    管理3.0
    偶感
    Javascript事件总结
    HTML5中与页面显示相关的API
    毕业了五年了--- 人生感想
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6574449.html
Copyright © 2011-2022 走看看