仙人掌的同构(hash)

关于仙人掌的同构,主要是我太蒟蒻了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[300000];
 31     ent e[500000];
 32     ent r[500000];
 33     ult st[1000000];
 34     int rt[2];
 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)==1)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=1;
 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*2>sqn+n)
 96                 fl=false;
 97         }
 98         if((sqn+n-p[x].wgt)*2>sqn+n)
 99             fl=false;
100         if(fl)
101         {
102             if(rt[0])
103             {
104                 rt[1]=x;
105             }else{
106                 rt[0]=x;
107             }
108         }
109     }
110     void Hash(int x,int f)
111     {
112         int top=0;
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+1,st+top+1,cmp);
128             p[x].has=seed1;
129             for(int i=1;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=1;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=1;
170         for(int i=1;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(1,0);
179         gravity(1,0);
180         r_ade(0,rt[0]);
181         if(rt[1])
182         {
183             r_ade(0,rt[1]);
184             for(int i=p[rt[0]].sh;i;i=r[i].lst)
185             {
186                 if(r[i].twd==rt[1])
187                     r[i].twd=0;
188             }
189             for(int i=p[rt[1]].sh;i;i=r[i].lst)
190             {
191                 if(r[i].twd==rt[0])
192                     r[i].twd=0;
193             }
194         }
195         Hash(0,0);
196         return p[0].has;
197     }
198 }C[2];
199 int main()
200 {
201     scanf("%d%d",&nt,&mt);
202     if(C[0].solve(nt,mt)==C[1].solve(nt,mt))
203     {
204         printf("YES
");
205     }else{
206         printf("NO
");
207     }
208     return 0;
209 }

大概就是这样了^_^

原文地址:https://www.cnblogs.com/blog-Dr-J/p/9479054.html