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

 

posted @ 2018-01-15 14:57  Sinogi  阅读(581)  评论(0编辑  收藏  举报