关于仙人掌的同构,主要是我太蒟蒻了QAQ,问了好几位大佬才弄好。

手撕仙人掌,你得先有手套 ,你得先了解以下基本知识

a.点双连通分量,没什么好说得,仙人掌上有环,判环用点双

b.树的hash点这里

c.仙人掌点这里                              

对于一棵仙人掌,我们通过一些方法来简化:                 

我们最讨厌的是环,假如说没有环,那么树的hash还是蛮简单的。          

OK那么就是圆方树了,如果你还不知道什么是圆方树,请自行百度或者点这里。

当然对于判定仙人掌的同构,不需要一颗完整的圆方树,只需要在环中间建点

单纯地表示一个环,使用最小表示法(这部分内容我稍后补充QAQ)

单纯地表示一棵树,hash。

嗯,如果你觉得我上面说得十分模糊,那么是正确的,因为还没有开始呢  ^_^

(我其实是不会告诉你我没有用tarjan和完整的圆方树的)

e.g.一个只有一个环的仙人掌

假设我们是这样搜索的

那么在dfs的过程中,要判定一个点在不在环上,记录它的父节点这样在回溯到4时,发现他有一个不是自己儿子的子节点(9)

哈,那就是环的另一端了。

这时抓出9,一直回溯父亲直到4被枚举到,整个环就被揪了出来。

新建一个节点,(在圆方树里则称方点)依次连边。

而对于非环上边直接连就好了

像这样就建立了一个独立出原图的树(一位大佬是这样描述的)

多么优雅的一棵树

好了,现在它是无根的找一下树的重心

新建一个根节点hash一下就好了^_^

你真的觉得这就完了

你太天真了

环是不能这样子搞的

正确打开方式:

别忘了真正的环上点是有顺序的

假如说这个环的方点(中间那个新建点)是根,跑最小表示法(然而我代码里没有这一项QAQ我改天加上)

对于一个普通树节点比如说这样

这样就可以了

代码实现

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. typedef unsigned long long ult;
  6. const ult seed1=1324983271ull;
  7. const ult seed2=4327894239ull;
  8. const ult lth1=9301248721ull;
  9. const ult lth2=8317498371ull;
  10. int nt,mt;
  11. bool cmp(ult x,ult y)
  12. {
  13. return x<y;
  14. }
  15. struct pnt{
  16. int hd;
  17. int sh;
  18. int fa;
  19. int wgt;
  20. bool ong;
  21. bool vis;
  22. bool chkd;
  23. ult has;
  24. };
  25. struct ent{
  26. int twd;
  27. int lst;
  28. };
  29. struct Cactus{
  30. pnt p[];
  31. ent e[];
  32. ent r[];
  33. ult st[];
  34. int rt[];
  35. int n,m;
  36. int sqn;
  37. int cnt;
  38. int cmt;
  39. void e_ade(int f,int t)
  40. {
  41. cnt++;
  42. e[cnt].twd=t;
  43. e[cnt].lst=p[f].hd;
  44. p[f].hd=cnt;
  45. }
  46. void r_ade(int f,int t)
  47. {
  48. cmt++;
  49. r[cmt].twd=t;
  50. r[cmt].lst=p[f].sh;
  51. p[f].sh=cmt;
  52. }
  53. void tr_dfs(int x,int f)
  54. {
  55. p[x].vis=true;
  56. for(int i=p[x].hd;i;i=e[i].lst)
  57. {
  58. int to=e[i].twd;
  59. if((i^f)==)continue;
  60. if(!p[to].vis)
  61. {
  62. p[to].fa=x;
  63. p[x].ong=false;
  64. tr_dfs(to,i);
  65. if(!p[x].ong)
  66. {
  67. r_ade(x,to);
  68. r_ade(to,x);
  69. }
  70. }else{
  71. if(p[to].chkd)continue;
  72. sqn++;
  73. int u=x;
  74. for(u=x;;u=p[u].fa)
  75. {
  76. r_ade(n+sqn,u);
  77. r_ade(u,n+sqn);
  78. p[u].ong=true;
  79. if(u==to)break;
  80. }
  81. }
  82. }
  83. p[x].chkd=true;
  84. }
  85. void gravity(int x,int f)
  86. {
  87. p[x].wgt=;
  88. bool fl=true;
  89. for(int i=p[x].sh;i;i=r[i].lst)
  90. {
  91. int to=r[i].twd;
  92. if(to==f)continue;
  93. gravity(to,x);
  94. p[x].wgt+=p[to].wgt;
  95. if(p[to].wgt*>sqn+n)
  96. fl=false;
  97. }
  98. if((sqn+n-p[x].wgt)*>sqn+n)
  99. fl=false;
  100. if(fl)
  101. {
  102. if(rt[])
  103. {
  104. rt[]=x;
  105. }else{
  106. rt[]=x;
  107. }
  108. }
  109. }
  110. void Hash(int x,int f)
  111. {
  112. int top=;
  113. for(int i=p[x].sh;i;i=r[i].lst)
  114. {
  115. int to=r[i].twd;
  116. if(to==f)continue;
  117. Hash(to,x);
  118. }
  119. if(x<=n)
  120. {
  121. for(int i=p[x].sh;i;i=r[i].lst)
  122. {
  123. int to=r[i].twd;
  124. if(to==f)continue;
  125. st[++top]=p[to].has;
  126. }
  127. sort(st+,st+top+,cmp);
  128. p[x].has=seed1;
  129. for(int i=;i<=top;i++)
  130. {
  131. p[x].has=((p[x].has*lth1+st[i])^st[i])+st[i];
  132. }
  133. }else{
  134. int i;
  135. for(i=p[x].sh;i;i=r[i].lst)
  136. {
  137. if(r[i].twd==f)
  138. break;
  139. }
  140. for(i=r[i].lst;i;i=r[i].lst)
  141. {
  142. int to=r[i].twd;
  143. st[++top]=p[to].has;
  144. }
  145. for(i=p[x].sh;i;i=r[i].lst)
  146. {
  147. int to=r[i].twd;
  148. if(to==f)
  149. break;
  150. st[++top]=p[to].has;
  151. }
  152. ult tmp1=seed2,tmp2=seed2;
  153. for(i=;i<=top;i++)
  154. {
  155. tmp1=((tmp1*lth2+st[i])^st[i])+st[i];
  156. }
  157. for(i=top;i;i--)
  158. {
  159. tmp2=((tmp2*lth2+st[i])^st[i])+st[i];
  160. }
  161. p[x].has=min(tmp1,tmp2);
  162. p[x].has*=lth2;
  163. }
  164. }
  165. ult solve(int nn,int mm)
  166. {
  167. n=nn;
  168. m=mm;
  169. cnt=;
  170. for(int i=;i<=m;i++)
  171. {
  172. int x;
  173. int y;
  174. scanf("%d%d",&x,&y);
  175. e_ade(x,y);
  176. e_ade(y,x);
  177. }
  178. tr_dfs(,);
  179. gravity(,);
  180. r_ade(,rt[]);
  181. if(rt[])
  182. {
  183. r_ade(,rt[]);
  184. for(int i=p[rt[]].sh;i;i=r[i].lst)
  185. {
  186. if(r[i].twd==rt[])
  187. r[i].twd=;
  188. }
  189. for(int i=p[rt[]].sh;i;i=r[i].lst)
  190. {
  191. if(r[i].twd==rt[])
  192. r[i].twd=;
  193. }
  194. }
  195. Hash(,);
  196. return p[].has;
  197. }
  198. }C[];
  199. int main()
  200. {
  201. scanf("%d%d",&nt,&mt);
  202. if(C[].solve(nt,mt)==C[].solve(nt,mt))
  203. {
  204. printf("YES\n");
  205. }else{
  206. printf("NO\n");
  207. }
  208. return ;
  209. }

大概就是这样了^_^

仙人掌的同构(hash)的更多相关文章

  1. BZOJ4337: BJOI2015 树的同构(hash 树同构)

    题意 题目链接 Sol 树的同构问题,直接拿hash判一下,具体流程大概是这样的: 首先转化为有根树,预处理出第\(i\)棵树以\(j\)为根时的hash值. 那么两个树同构当且仅当把两棵树的hash ...

  2. luogu P5043 【模板】树同构 hash 最小表示法

    LINK:模板 树同构 题目说的很迷 给了一棵有根树 但是重新标号 言外之意还是一棵无根树 然后要求判断是否重构. 由于时无根的 所以一个比较显然的想法暴力枚举根. 然后做树hash或者树的最小表示法 ...

  3. 仙人掌&圆方树学习笔记

    仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...

  4. bzoj3871: [Neerc2013 C]Cactus Automorphisms || 3899: 仙人掌树的同构

    Description 给定一个N,N<=50 000个节点的仙人掌,其是指每条边最多在一个环中的无向图,求仙人掌有多少种自同构.自同构是指得是图的顶点集合V到V的变换M, 以P1^a1*P2^ ...

  5. BZOJ 4337: BJOI2015 树的同构 树hash

    4337: BJOI2015 树的同构 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4337 Description 树是一种很常见的数 ...

  6. 【NOI2013模拟】坑带的树(仙人球的同构+圆方树乱搞+计数+HASH)

    [NOI2013模拟]坑带的树 题意: 求\(n\)个点,\(m\)条边的同构仙人球个数. \(n\le 1000\) 这是一道怎么看怎么不可做的题. 这种题,肯定是圆方树啦~ 好,那么首先转为广义圆 ...

  7. BZOJ3899 仙人掌树的同构(圆方树+哈希)

    考虑建出圆方树.显然只有同一个点相连的某些子树同构会产生贡献.以重心为根后(若有两个任取一个即可),就只需要处理子树内部了. 如果子树的根是圆点,其相连的同构子树可以任意交换,方案数乘上同构子树数量的 ...

  8. BZOJ4337:[BJOI2015]树的同构(树hash)

    Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如 ...

  9. 刷题总结——树的同构(bzoj4337 树上hash)

    Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如 ...

随机推荐

  1. hdu(1069)——Monkey and Banana(LIS变形)

    题意: 如今给你n个石块,然后它由坐标来表示(x,y,z).可是它能够有不同的方法,也就是说它的三个坐标能够轮换着来的. 石块的数量不限,可是每次都必须保持上底面的长和宽严格递减,然后问你用这些石块所 ...

  2. iBatis框架使用 4步曲

    iBatis是一款使用方便的数据訪问工具,也可作为数据持久层的框架.和ORM框架(如Hibernate)将数据库表直接映射为Java对象相比.iBatis是将SQL语句映射为Java对象. 相对于全自 ...

  3. android YUV Sensor配置Camera应用的flash auto菜单

    请在Config.ftbl.flashlight.h (mediatek\custom\common\hal\flashlight\src)中. 将全部的两处凝视掉的code: //CameraPar ...

  4. vue3事件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 19. idea 创建多模块依赖Maven项目

    转自:https://www.cnblogs.com/runnerjack/p/9269526.html 本来网上的教程还算多,但是本着自己有的才是自己的原则,还是自己写一份的好,虽然可能自己也不会真 ...

  6. 有关R6034错误的思考

    作者:朱金灿 来源:http://blog.csdn.net/clever101 我们有时会遇到R6034错误,工程明明编译通过,但是运行时却出现: 网上的解决办法很多,但是有效的不多,特别是对阐述这 ...

  7. Lambda表达式相当于一个函数

    看来你对Lambda完全不懂.Lambda表达式相当于一个函数. 比如model => model.Name相当于string 一个函数(Model的类型 model) {     return ...

  8. Hexo 相册实践

    灵感 想给自已的blog添加一个相册功能.给生活中的点点滴滴留影记录.搜寻网络上给Next主题添加相册功能的基本上没有,只能重头到尾开始一点点的实践.    大致的想法:  1. 相册展示类似于归档一 ...

  9. 超好用的谷歌浏览器、Sublime Text、Phpstorm、油猴插件合集

    原文:超好用的谷歌浏览器.Sublime Text.Phpstorm.油猴插件合集 - 『精品软件区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|www.52pojie.c ...

  10. 手把手教你用vue-cli构建一个简单的路由应用

    上一章说道:十分钟上手-搭建vue开发环境(新手教程)https://www.jianshu.com/p/0c6678671635 开发环境搭建好之后,那么开始新添加一些页面,构建最基本的vue项目, ...