bzoj4754 [Jsoi2016]独特的树叶 (树同构)
4754: [Jsoi2016]独特的树叶
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 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 }
散りぬべき 時知りてこそ 世の中の 花も花なれ 人も人なれ