• bzoj4754 [Jsoi2016]独特的树叶 (树同构)


    4754: [Jsoi2016]独特的树叶

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 168  Solved: 67
    [Submit][Status][Discuss]

    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中编号最小的那一个的编号
     
     
    枚举$B$中叶子节点,删去后判断是否与$A$同构即可,用哈希实现;
    树哈希通常用最小表示法,对于一棵有根树,先给每个点赋一个点权,大小等于它的子树大小;
    然后对于一个节点,把它的儿子的哈希值排序后,它的哈希值就等于“它的点权+它的儿子的哈希值”组成的串的哈希值;
    因为是无根树,需要加上换根操作,排序后记一下串的前后缀哈希值即可;
    AC GET☆DAZE
     
    ↓代码
      1 #include<algorithm>
      2 #include<iostream>
      3 #include<complex>
      4 #include<cstring>
      5 #include<string>
      6 #include<cstdio>
      7 #include<vector>
      8 #include<cmath>
      9 #include<queue>
     10 #include<map>
     11 #include<set>
     12 #define N 100039
     13 #define mod 20070831
     14 #define inf 0x3f3f3f3f
     15 #define ll unsigned long long
     16 using namespace std;
     17 struct edge
     18 {
     19     int to,next;
     20 }net[N<<1];
     21 struct poi
     22 {
     23     int n;
     24     ll w,suf;
     25     bool friend operator < (poi a,poi b)
     26     {
     27         return a.w<b.w;
     28     }
     29 };
     30 int n,tot,head[N],siz[N],deg[N];
     31 ll bs[N],hs[N];
     32 vector<poi> son[N];
     33 map<ll,int> mp;
     34 void add(int u,int v)
     35 {
     36     net[++tot]=(edge){v,head[u]},head[u]=tot,deg[u]++;
     37     net[++tot]=(edge){u,head[v]},head[v]=tot,deg[v]++;
     38 }
     39 void get_base(ll base,int lim)
     40 {
     41     bs[0]=1;
     42     for(int a=1;a<=lim;a++)
     43     {
     44         bs[a]=bs[a-1]*base;
     45     }
     46 }
     47 void calc_hash(int pos,int sz)
     48 {
     49     sort(son[pos].begin(),son[pos].end());
     50     hs[pos]=0;
     51     for(int a=0,b=son[pos].size();a<b;a++)
     52     {
     53         hs[pos]+=bs[a+1]*son[pos][a].w;
     54     }
     55     hs[pos]+=sz;
     56 }
     57 void dfs(int pos,int pre)
     58 {
     59     siz[pos]=1;
     60     for(int a=head[pos];a;a=net[a].next)
     61     {
     62         if(net[a].to!=pre)
     63         {
     64             dfs(net[a].to,pos);
     65             siz[pos]+=siz[net[a].to];
     66             son[pos].push_back((poi){net[a].to,hs[net[a].to],hs[net[a].to]});
     67         }
     68     }
     69     calc_hash(pos,siz[pos]);
     70 }
     71 void change(int pos,int pre,ll hs_pre)
     72 {
     73     if(pre)
     74     {
     75         son[pos].push_back((poi){pre,hs_pre,hs_pre});
     76         calc_hash(pos,n);
     77     }
     78     for(int a=son[pos].size()-2,b=0;~a;a--)
     79     {
     80         son[pos][a].suf+=son[pos][a+1].suf*bs[1];
     81     }
     82     ll stp=0;
     83     son[pos].push_back((poi){0,0,0}); 
     84     for(int a=0,b=son[pos].size()-1;a<b;a++)
     85     {
     86         if(son[pos][a].n!=pre)
     87         {
     88             change(son[pos][a].n,pos,stp+bs[a+1]*son[pos][a+1].suf+n-siz[son[pos][a].n]);
     89         }
     90         stp+=bs[a+1]*son[pos][a].w;
     91     }
     92 }
     93 void Clear()
     94 {
     95     tot=0;
     96     memset(head,0,sizeof(head));
     97     memset(deg,0,sizeof(deg));
     98     memset(hs,0,sizeof(hs));
     99     for(int a=1;a<=n;a++)
    100     {
    101         son[a].clear();
    102     }
    103 }
    104 int main()
    105 {
    106     scanf("%d",&n);
    107     get_base(1011139,n);
    108     for(int a=1,b,c;a<n;a++)
    109     {
    110         scanf("%d%d",&b,&c);
    111         add(b,c);
    112     }
    113     dfs(1,0);
    114     change(1,0,0);
    115     for(int a=1;a<=n;a++)
    116     {
    117         mp[hs[a]]=1;
    118     }
    119     Clear(),n++;
    120     for(int a=1,b,c;a<n;a++)
    121     {
    122         scanf("%d%d",&b,&c);
    123         add(b,c);
    124     }
    125     dfs(1,0);
    126     change(1,0,0);
    127     for(int a=1;a<=n;a++)
    128     {
    129         if(deg[a]==1)
    130         {
    131             if(mp[son[net[head[a]].to][1].suf*bs[1]+n-1])
    132             {
    133                 printf("%d",a);
    134                 break;
    135             }
    136         }
    137     }
    138     return 0;
    139 }
    bzoj4754
  • 相关阅读:
    【Selenium IDE】下载安装Chrome和Firefox插件IDE ide了解就行 不是重点 重点是写脚本
    调用接口时,生产环境,路径加斜杠“/”和不加的区别
    WPF 踩坑笔记12 DataGrid触发选中行事件
    WPF 踩坑笔记11 线程取消
    WPF 踩坑笔记10 ListBox异步动态加载
    WPF 踩坑笔记9 直接打印
    思维的体操
    【洛谷 P4213】 【模板】杜教筛(Sum)
    【洛谷 P2257】 YY的GCD(莫比乌斯反演)
    【洛谷 P4980】 【模板】Pólya 定理
  • 原文地址:https://www.cnblogs.com/Sinogi/p/8288079.html
Copyright © 2020-2023  润新知