判断两棵无根树是否同构只需要把重心提作根哈希即可。由于只添加了一个叶子,重心的位置几乎不发生偏移,所以直接把两棵树的重心提起来,逐层找哈希值不同且对应的两子树即可。被一个普及组子问题卡一年。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define ul unsigned long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{int x=0,f=1;char c=getchar();while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;
}
int n,ans,f[N],g[N];
struct tree
{int p[N],t,size[N],root;ul hax[N],f[N];struct data{int to,nxt;}edge[N<<1];void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}void dfs(int k,int from){size[k]=1;for (int i=p[k];i;i=edge[i].nxt)if (edge[i].to!=from)dfs(edge[i].to,k),size[k]+=size[edge[i].to];}int findroot(int k,int s){int mx=0;for (int i=p[k];i;i=edge[i].nxt)if (size[edge[i].to]<size[k]&&size[edge[i].to]>size[mx]) mx=edge[i].to;if (size[mx]*2>s) return findroot(mx,s);else return k;}void refind(){for (int i=p[root];i;i=edge[i].nxt)if (size[edge[i].to]*2>=size[root]) {root=edge[i].to;break;}}void gethash(int k,int from){for (int i=p[k];i;i=edge[i].nxt)if (edge[i].to!=from) gethash(edge[i].to,k);int cnt=0;for (int i=p[k];i;i=edge[i].nxt)if (edge[i].to!=from) f[++cnt]=hax[edge[i].to];sort(f+1,f+cnt+1);hax[k]=0;for (int i=1;i<=cnt;i++) hax[k]=hax[k]*107+f[i];hax[k]+=size[k]*509;}
}a,b;
bool cmp(const int&x,const int&y)
{return a.hax[x]<a.hax[y];
}
bool cmp2(const int&x,const int&y)
{return b.hax[x]<b.hax[y]||b.hax[x]==b.hax[y]&&x>y;
}
void work(int x,int y)
{int cnt=0,cnt2=0;for (int i=a.p[x];i;i=a.edge[i].nxt)if (a.size[a.edge[i].to]<a.size[x]) f[++cnt]=a.edge[i].to; for (int i=b.p[y];i;i=b.edge[i].nxt)if (b.size[b.edge[i].to]<b.size[y]) g[++cnt2]=b.edge[i].to; sort(f+1,f+cnt+1,cmp);sort(g+1,g+cnt2+1,cmp2);if (cnt>cnt2||cnt2>cnt+1) return;if (cnt2==cnt+1){int t=0;for (int i=1,j=1;i<=cnt2;i++,j++)if (a.hax[f[j]]!=b.hax[g[i]]||j>cnt) if (!t) t=g[i++];else return;if (t) ans=min(ans,t);return;}if (cnt2==cnt){int u,v;for (u=1;u<=cnt;u++) if (a.hax[f[u]]!=b.hax[g[u]]) break;if (!u) return;if (a.hax[f[u]]<b.hax[g[u]]) for (v=u;v<cnt;v++) if (a.hax[f[v+1]]!=b.hax[g[v]]) break;if (!v) return;for (int i=v+1;i<=cnt;i++) if (a.hax[f[i]]!=b.hax[g[i]]) return;for (int i=1;i<=cnt;i++) if (b.hax[g[v]]==b.hax[g[i]]) work(f[u],g[i]);}
}
int main()
{
#ifndef ONLINE_JUDGEfreopen("bzoj4754.in","r",stdin);freopen("bzoj4754.out","w",stdout);const char LL[]="%I64d\n";
#elseconst char LL[]="%lld\n";
#endifn=read();ans=n+1;for (int i=1;i<n;i++){int x=read(),y=read();a.addedge(x,y),a.addedge(y,x);}for (int i=1;i<=n;i++){int x=read(),y=read();b.addedge(x,y),b.addedge(y,x);}a.dfs(1,1),b.dfs(1,1);a.root=a.findroot(1,n),b.root=b.findroot(1,n+1);a.dfs(a.root,a.root),b.dfs(b.root,b.root);a.gethash(a.root,a.root),b.gethash(b.root,b.root);work(a.root,b.root);if (n&1) a.refind();else b.refind();a.dfs(a.root,a.root),b.dfs(b.root,b.root);a.gethash(a.root,a.root),b.gethash(b.root,b.root);work(a.root,b.root);cout<<ans;return 0;
}

转载于:https://www.cnblogs.com/Gloid/p/9961329.html

BZOJ4754 JSOI2016独特的树叶(哈希)相关推荐

  1. P5043 【模板】树同构([BJOI2015]树的同构 // P4323 [JSOI2016]独特的树叶

    一.P5043 [模板]树同构([BJOI2015]树的同构): #include<iostream> #include<cstdio> #include<algorit ...

  2. 洛谷 - P4323 [JSOI2016]独特的树叶(树上哈希+换根dp)

    题目链接:点击查看 题目大意:给出一棵 n 个节点的树 A ,再给出一棵 n + 1 个节点的树 B,题目保证了树 B 是树 A 添加了一个叶子结点后的一棵树,只不过编号的顺序不同,现在问这个叶子节点 ...

  3. 【BZOJ - 4754】独特的树叶(树哈希)

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

  4. P4323-[JSOI2016]独特的树叶【换根dp,树哈希】

    正题 题目链接:https://www.luogu.com.cn/problem/P4323 题目大意 给出nnn个点的树和加上一个点之后的树(编号打乱). 求多出来的是哪个点(如果有多少个就输出编号 ...

  5. [暑假的bzoj刷水记录]

    (这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊  堆一起算了 隔一段更新一下.  7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...

  6. 哈希算法在判定树同构方面的应用(下)

    哈希算法在判定树同构方面的应用 在上一篇文章中我们介绍了 枚举根节点哈希 和 求重心哈希 两种方法来判断两棵无根树是否同构. 但是如果有些题目中我必须要计算出每个根节点的 fff 值,且 n≤1e5n ...

  7. 【公告】xx 网络白皮书和Praxxis 技术文件正式发布

    2019年12月4日,大开曼岛--David Chaum和Praxxis团队宣布发布xx网络白皮书和Praxxis技术文件.这些文件提供了关于xx网络和xx币的详细信息和见解,这是一种革命性的区块链和 ...

  8. 怎样设计一个好玩的游戏——游戏设计的艺术

    前言: 一个好玩的游戏,就是要让玩家在玩游戏的过程中感到愉快的游戏体验.游戏品质一般可以分为三个层次:普通.精品.经典. 仅仅要游戏能赚钱的好游戏可算是精品游戏,而经典的游戏,必定有深厚的游戏内涵,甚 ...

  9. OnlyOffice配置文档

    OnlyOffice配置参数文档 更多内容可以访问官方文档 https://api.onlyoffice.com/editors/basic 1.基础参数 参数名称 类型 描述 例子 document ...

最新文章

  1. JavaScript可否多线程? 深入理解JavaScript定时机制
  2. php项目导入其他包,将一个外部项目导入Thinkphp环境中
  3. stm32基本入门(一)
  4. SSD 超详细入门(代码+原文)
  5. 案例分析|能源行业大数据案例分析
  6. Grounded video description
  7. scratch趣味编程——挖矿小游戏
  8. 项目进度管理方法——里程碑式管理
  9. 音频处理与压缩技术漫谈
  10. 物联网应用技术有哪些?
  11. python为在线漫画站点自制非官方API(未完待续)
  12. C语言time.h中srand(),rand()等等函数产生随机数的用法。
  13. 光照与渲染(十)- 自发光材质
  14. 【微信小程序】WXML模板语法 —— 数据绑定
  15. Atcode120E 1D Party
  16. Oracle存储过程中loop、for循环的用法
  17. 语音特征MFCC和PLP
  18. Spring MVC源码 ----- @RequestBody和@ResponseBody原理解析
  19. 【Windows C++】powershell 获取chrome密码并上传
  20. 预约快递取件接口API对接demo

热门文章

  1. ThreadLocal是否会引发内存泄露的分析 good
  2. JAVA中操作符的优先级
  3. [iOS] 在UIToolBar中增加UILabel等控件(xib/storyboard图形界面方式)
  4. Eclipse常见问题集锦
  5. postfix 554-5.7.0 Reject
  6. java.sql.SQLException: Zero date value prohibited 报错分析
  7. 2. Oracle 数据库实例启动关闭过程
  8. JQuery笔记(二)jq常用方法animate()
  9. 802.15.4的超帧
  10. Android输入输出机制之来龙去脉