独特的树叶

Posted betablewaloot

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了独特的树叶相关的知识,希望对你有一定的参考价值。

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;
        }
    }
} 

以上是关于独特的树叶的主要内容,如果未能解决你的问题,请参考以下文章

JSOI2016独特的树叶

[JSOI2016]独特的树叶

[JSOI2016]独特的树叶

bzoj 4754: [Jsoi2016]独特的树叶

bzoj4754: [Jsoi2016]独特的树叶

Luogu P4323 [JSOI2016]独特的树叶