洛谷 P4323 [JSOI2016]独特的树叶 树hash

版权声明:2333 https://blog.csdn.net/liangzihao1/article/details/89010095

题目描述

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

输入输出格式

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

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

输入输出样例

输入样例#1:
5
1 2
2 3
1 4
1 5
1 2
2 3
3 4
4 5
3 6
输出样例#1:
1

说明
对于所有数据, 1 n 1 0 5 1≤n≤10^5

分析:
显然是树hash的题目。
对于树 A A ,我们要求出每一个点为根的hash值。树 B B 要求出每一个叶子为根的hash值。
可以使用二次dfs的方式求得。设 f [ i ] f[i] 为当前节点的hash值, g [ i ] g[i] 为以 i i 为根的子树hash值。
考虑一个点的hash值为所有儿子的 g [ j ] k e y + s i z e [ j ] g[j]*key+size[j] 的异或和,其中 k e y key 为位值,这里不用加起来取模的方式,采用异或可以更好算 f f 。只要可以通过再异或一个儿子达到去掉的结果。
对于B来说,去掉某个叶子节点的hash值等于他父亲的hash值异或上这个去掉叶子的hash值。所以我们要选一个不是叶子的节点做根。

代码:

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
#define LL long long

const int maxn=1e5+7;
const int key=10189488;
const LL mod=1e9+7;

using namespace std;

int n,x,y;
int deg[maxn];

map <int,int> h;

struct tree{
    int n,cnt;
    int size[maxn],ls[maxn];
    int f[maxn],g[maxn],fa[maxn];
    struct edge{
        int y,next;
    }e[maxn*2];
    void add(int x,int y)
    {
        e[++cnt]=(edge){y,ls[x]};
        ls[x]=cnt;
    }
    int get(int x,int y)
    {
        return ((LL)x*(LL)key+y)%mod;
    }
    void dfs1(int x,int F)
    {
        g[x]=size[x]=1;
        fa[x]=F;
        for (int i=ls[x];i>0;i=e[i].next)
        {
            int y=e[i].y;
            if (y==fa[x]) continue;
            dfs1(y,x);
            size[x]+=size[y];
            g[x]^=get(g[y],size[y]);
        }
    }
    void dfs2(int x)
    {
        if (!fa[x]) f[x]=g[x];
            else f[x]=g[x]^get(f[fa[x]]^get(g[x],size[x]),n-size[x]);
        for (int i=ls[x];i>0;i=e[i].next)
        {
            int y=e[i].y;
            if (y==fa[x]) continue;
            dfs2(y);
        }
    }
    int check(int x)
    {
        return f[fa[x]]^get(g[x],1);
    }
}A,B;

bool isleaf(int x)
{
    return deg[x]==1;
}

int main()
{
//	freopen("data.in","r",stdin);
    scanf("%d",&A.n);
    for (int i=1;i<A.n;i++)
    {
        scanf("%d%d",&x,&y);
        A.add(x,y);
        A.add(y,x);
    }
    A.dfs1(1,0),A.dfs2(1);	
    for (int i=1;i<=A.n;i++) h[A.f[i]]=1;
    B.n=A.n+1;
    for (int i=1;i<B.n;i++)
    {
        scanf("%d%d",&x,&y);
        B.add(x,y);
        B.add(y,x);
        deg[x]++,deg[y]++;
    }	
    for (int i=1;i<=B.n;i++)
    {
        if (!isleaf(i))
        {
            B.dfs1(i,0);
            B.dfs2(i);
            break;
        }
    }				
    for (int i=1;i<=B.n;i++)
    {
        if (isleaf(i))
        {
            int k=B.check(i);
            if (h[k])
            {
                printf("%d",i);
                break;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/89010095
今日推荐