zoukankan      html  css  js  c++  java
  • 独特的树叶

    1695:独特的树叶

    时间限制: 1000 ms         内存限制: 262144 KB

    【题目描述】

    JYY有两棵树A和B:树A有N个点,编号为1到N;树B有N+1个节点,编号为1到N+1。

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


    【输入】

    输入一行包含一个正整数N。

    接下来N-1行,描述树A,每行包含两个整数表示树A中的一条边;

    接下来N行,描述树B,每行包含两个整数表示树B
    中的一条边。
    【输出】

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

    【数据规模】

    1<=n<=1e5.

    【题解】

    判断两棵无根树是否同构,则需在它们中分别有一个根u,和根v,使得树A以u为根的哈希值等于B以v为根的哈希值。

    那么我们只需要求出A树以每一个点为根的哈希值装入map中,在判断B去掉了一个叶子节点(入出度为1)后以任一根的哈希值是否在map中即可。

    考虑有根树哈希值。

    这里的公式为:

    将u的子节点按f值大小排序,令ch[i]=131的i次方。

    f[u]=siz[u]*∑f[v]*ch[i-1];(i:1--u子节点个数)

    那么我们可以在O(nlogn)时间内求出以1号点为根的所有f值。

    现在要求出以任一点为根的根的f值.

    考虑换根树形DP。

    设g[u]为以u的父亲为根时,去掉u及其子树中所有点后的哈希值。(注意是以u的父亲为根

    则对于u的儿子节点

    令hu数组表示除去f[v]外的u所有儿子的f值,如果u不为1,则加入g[u].

    g[v]=(n-siz[v])∑hu[i]*ch[i-1]。

    排序后对hu数组求一个前缀和和后缀和即可O(1)求出每个g[v]。

    ans[u]表示以u为根的整棵树哈希值。

    ans[u]即为g[v]式子不去掉f[v]所求出的值。

    将每个ans加入map中。

    对于B树的每个叶节点,去掉它后树的哈希值则为以它为根节点的ans/(n+1) 取质数模数求逆元可得   (有哈希定义得到)

    判断得求出的值在map中就输出。

    代码如下:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=1e5+5;
    const int mo=1e9+9;
    const int cc=131;
    int gsn,huan[N],pre[N],sub[N],ch[N];
    map <int,int> ma;
    struct pigu
    {
        int dao,ne;
    };
    struct choujiao
    {
        int hao,zhi;
    }dahuan[N];
    inline bool cmp(choujiao x,choujiao y)
    {
        return x.zhi<y.zhi;
    }
    struct tree
    {
        int n,size,last[N],siz[N],cnt[N],g[N];
        int f[N],ans[N];
        pigu a[N<<1];
        inline void lingjiebiao(int x,int y)
        {
            a[++size].dao=y;
            a[size].ne=last[x];
            last[x]=size;
            cnt[x]++;
        }
        inline void get_f(int now,int fa)
        {
            siz[now]=1;
            int cnt=0;
            for(int i=last[now];i;i=a[i].ne)
            {
                if(a[i].dao==fa) continue;
                get_f(a[i].dao,now);
                siz[now]+=siz[a[i].dao];
            }
            for(int i=last[now];i;i=a[i].ne)
            {
                if(a[i].dao==fa) continue;
                huan[++cnt]=f[a[i].dao];
            }
            sort(huan+1,huan+cnt+1);
            for(int i=1;i<=cnt;i++)
                f[now]+=(huan[i]*ch[i-1])%mo;
            f[now]*=siz[now];f[now]%=mo;
            if(!cnt) f[now]=1;
        }
        inline void get_ans(int now,int fa)
        {
            int cnt=0;
            for(int i=last[now];i;i=a[i].ne)
            {
                if(a[i].dao==fa) continue;
                dahuan[++cnt]={a[i].dao,f[a[i].dao]};
            }
            if(fa) dahuan[++cnt]={-1,g[now]};
            sort(dahuan+1,dahuan+cnt+1,cmp);
            pre[0]=sub[cnt+1]=0;
            for(int i=1;i<=cnt-1;i++) pre[i]=(pre[i-1]+(dahuan[i].zhi*ch[i-1])%mo)%mo;
            for(int i=cnt;i>=2;i--) sub[i]=(sub[i+1]+(dahuan[i].zhi*ch[i-2])%mo)%mo;
            for(int i=1;i<=cnt;i++)
            {
                if(dahuan[i].hao==-1) continue;
                g[dahuan[i].hao]=((n-siz[dahuan[i].hao])*(pre[i-1]+sub[i+1])%mo+mo)%mo;
                g[dahuan[i].hao]%=mo;
            }
            if(!fa&&cnt==1) g[dahuan[1].hao]=1;
            for(int i=1;i<=cnt;i++)
                ans[now]=(ans[now]+dahuan[i].zhi*ch[i-1]%mo)%mo;
            ans[now]*=n;ans[now]%=mo;
            for(int i=last[now];i;i=a[i].ne) if(a[i].dao!=fa) get_ans(a[i].dao,now);
        }
    }t1,t2;
    inline int read()
    {
        char c=getchar();
        int x=0,f=1;
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    inline int hapow(int ch,int ci)
    {
        int x=ch,gs=1;
        while(ci)
        {
            if(ci&1) gs=(gs*x)%mo;
            x=(x*x)%mo;
            ci>>=1;
        }
        return gs;
    }
    signed main()
    {
        gsn=read();ch[0]=1;
        for(int i=1;i<=gsn+2;i++) ch[i]=(ch[i-1]*cc)%mo;
        t1.n=gsn;t2.n=gsn+1;
        for(int i=1,x,y;i<=gsn-1;i++)
        {
            x=read();y=read();
            t1.lingjiebiao(x,y);
            t1.lingjiebiao(y,x);
        }
        for(int i=1,x,y;i<=gsn;i++)
        {
            x=read();y=read();
            t2.lingjiebiao(x,y);
            t2.lingjiebiao(y,x);
        }
        t1.get_f(1,0);t2.get_f(1,0);
        t1.get_ans(1,0);t2.get_ans(1,0);
        for(int i=1;i<=gsn;i++) 
        ma[t1.ans[i]]=1;
        for(int i=1;i<=gsn+1;i++)
        {
            if(t2.cnt[i]>1) continue;
            if(ma[(t2.ans[i]*hapow(gsn+1,mo-2))%mo]==1)
            {
                cout<<i;
                return 0;
            }
        }
    } 
  • 相关阅读:
    BFS(广搜训练题目)
    练习赛1(补题)
    练习赛1(AC题)
    codeup 1743: 算法3-4:表达式求值
    数学相关(更新ing)
    c语言常用函数(更新ing)
    大牛的博客(学习不止,更新不止)
    51nod 1005 大数加法
    js1-----预览js内容
    css10---转载---定位,浮动
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12146606.html
Copyright © 2011-2022 走看看