题目描述
树是一种很常见的数据结构。
我们把N个点,N-1条边的连通无向图称为树。
若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树。
对于两个树T1T_1T1​和T2T_2T2​,如果能够把树T1T_1T1​的所有点重新标号,使得树T1T_1T1​和树T2T_2T2​完全相同,那么这两个树是同构的。也就是说,它们具有相同的形态。
现在,给你M个有根树,请你把它们按同构关系分成若干个等价类。
输入格式
第一行,一个整数M。
接下来M行,每行包含若干个整数,表示一个树。第一个整数N表示点数。接下来N个整数,依次表示编号为1到N的每个点的父亲结点的编号。根节点父亲结点编号为0。
输出格式
输出M行,每行一个整数,表示与每个树同构的树的最小编号。

输入输出样例
输入 #1
4
4 0 1 1 2
4 2 0 2 3
4 0 1 1 1
4 0 1 2 3

输出 #1
1
1
3
1

说明/提示
编号为1, 2, 4 的树是同构的。编号为3 的树只与它自身同构。
100% 的数据中,1≤N,M≤501\leq N,M\leq501≤N,M≤50。

#include<stdio.h>
struct node{int ch[2];int size;int val;
};
node nn[4096];
int num;
void add(char* s,int n,int now){nn[now].size++;if(n==0){nn[now].val++;return;}if(!nn[now].ch[s[0]-'0']){num++;nn[num].ch[0]=0;nn[num].ch[1]=0;nn[num].size=0;nn[num].val=0;nn[now].ch[s[0]-'0']=num;}add(s+1,n-1,nn[now].ch[s[0]-'0']);
}
int query(char* s,int n,int now,int i){if(n==0){if(nn[now].val==0) nn[now].val=i;return nn[now].val;}if(!nn[now].ch[s[0]-'0']){num++;nn[num].ch[0]=0;nn[num].ch[1]=0;nn[num].size=0;nn[num].val=0;nn[now].ch[s[0]-'0']=num;}return query(s+1,n-1,nn[now].ch[s[0]-'0'],i);
}
void sol(char* s,int n){if(n==0) return;int lastwz=0;int cnt=0;for(int i=0;i<n;i++){if(s[i]=='0') cnt++;else cnt--;if(cnt==0){sol(s+lastwz+1,i-lastwz-1);lastwz=i+1;}}num=0;nn[num].ch[0]=0;nn[num].ch[1]=0;nn[num].size=0;nn[num].val=0;cnt=0;lastwz=0;for(int i=0;i<n;i++){if(s[i]=='0') cnt++;else cnt--;if(cnt==0){add(s+lastwz,i-lastwz+1,0);lastwz=i+1;}}int now=0;cnt=0;while(1){if(nn[now].size==0) break;nn[now].size--;if(nn[now].val){nn[now].val--;now=0;continue;}if(nn[now].ch[0]&&nn[nn[now].ch[0]].size){s[cnt]='0';now=nn[now].ch[0];}else{s[cnt]='1';now=nn[now].ch[1];}cnt++;}
}
char s[64][128];
int len[64];
int head[64],last[128],to[128],cnt=0;
int size[64];
void add(int u,int v){cnt++;last[cnt]=head[u];head[u]=cnt;to[cnt]=v;
}
void dfs(int u,int f){size[u]=1;for(int i=head[u];i;i=last[i]){int v=to[i];if(v==f) continue;dfs(v,u);size[u]+=size[v];}
}
int findroot(int u,int f,int n){for(int i=head[u];i;i=last[i]){int v=to[i];if(v==f) continue;if(size[v]<=n) continue;return findroot(v,u,n);}return u;
}
int tim;
void dfs2(int u,int f,int id){s[id][tim]='0';tim++;for(int i=head[u];i;i=last[i]){int v=to[i];if(v==f) continue;dfs2(v,u,id);}s[id][tim]='1';tim++;
}
int main(){int m;scanf("%d",&m);for(int i=1;i<=m;i++){int n;scanf("%d",&n);for(int j=1;j<=n;j++) head[j]=0;cnt=0;for(int j=1;j<=n;j++){int v;scanf("%d",&v);if(v){add(j,v);add(v,j);}}dfs(1,0);int u=findroot(1,0,n>>1);int v=0;for(int j=head[u];j;j=last[j]){if((size[to[j]]<<1)==n){v=to[j];break;}}tim=0;dfs2(u,v,i);if(v) dfs2(v,u,i);sol(s[i],tim);len[i]=tim;}num=0;nn[num].ch[0]=0;nn[num].ch[1]=0;nn[num].size=0;nn[num].val=0;for(int i=1;i<=m;i++) printf("%d\n",query(s[i],len[i],0,i));return 0;
}

洛谷-5043 【模板】树同构([BJOI2015]树的同构)相关推荐

  1. 洛谷·【模板】点分树 | 震波【including 点分树

    初见安-这里是传送门:洛谷P6329 [模板]点分树 | 震波 一.点分树 其实你会点分治的话,点分树就是把点分治时的重心提出来重新连城一棵树. 比如当前点是u,求出子树v的重心root后将root与 ...

  2. 信息学奥赛一本通 1365:FBI树(fbi) | 1928:【04NOIP普及组】FBI树 | 洛谷 P1087 [NOIP2004 普及组] FBI 树

    [题目链接] ybt 1365:FBI树(fbi) ybt 1928:[04NOIP普及组]FBI树 洛谷 P1087 [NOIP2004 普及组] FBI 树 [题目考点] 1. 二叉树 [解题思路 ...

  3. 专题·树链剖分【including 洛谷·【模板】树链剖分

    初见安~~~终于学会了树剖~~~ [兴奋]当初机房的大佬在学树剖的时候我反复强调过:"学树剖没有前途的!!!" 恩.真香. 一.重链与重儿子 所谓树剖--树链剖分,就是赋予一个链的 ...

  4. 洛谷P5069 [Ynoi2015]纵使日薄西山(树状数组,set)

    洛谷题目传送门 一血祭 向dllxl致敬! 算是YNOI中比较清新的吧,毕竟代码只有1.25k. 首先我们对着题意模拟,寻找一些思路. 每次选了一个最大的数后,它和它周围两个数都要减一.这样无论如何, ...

  5. 洛谷P5149——会议座位【字典树 + 逆序对】

    洛谷P5149--会议座位 大致思路:我们先用字典树把单词存起来,在每个单词的末尾节点给这个单词按照出现顺序标号,然后在查找的过程中,把其出现顺序用一个数组一次存起来,然后求这个数组的逆序对即可. # ...

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

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

  7. 洛谷 - P4755 Beautiful Pair(笛卡尔树+主席树)

    题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a,现在一个数对 ( i , j ) 如果满足 a[ i ] * a[ j ] <=max( a[ i ] ~ a[ j ] ),则称其 ...

  8. 洛谷.4897.[模板]最小割树(Dinic)

    题目链接 最小割树模板.具体见:https://www.cnblogs.com/SovietPower/p/9734013.html. ISAP不知为啥T成0分了.. Dinic: //1566ms ...

  9. 洛谷 p3372 模板-线段树 1

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个 ...

最新文章

  1. 【配置文件】log4j是什么log4j
  2. linux中重定向学习总结
  3. bootstrap轮播,播放到最后一张图片的时候,就不正确了。
  4. LVS(5)——关于ipvsadm第一次启动失败的原因
  5. 【转】oracle 和 ' 特殊字符处理 ( like 'GAC/_%' escape ''; 这里面的 / 居然将 转义了 为什么?)...
  6. QT之 Hello World
  7. aws rds监控慢sql_AWS RDS SQL Server的多可用区配置
  8. newifi3高恪魔改最新_12.08达达最新球球id账号呆瓜表
  9. 学习笔记--配置DHCP服务器(基于全局的地址池)
  10. .Net Log4Net配置多文件日志记录
  11. Scala安装和开发环境配置教程
  12. “手把手教你设计”—12个最佳手机APP界面设计教程
  13. 电脑如何登录两个微信
  14. 高频面试(十二):Elasticsearch和solar的区别
  15. flask-项目结构
  16. LayaBox---TypeScript---举例
  17. Docker-------网络模式
  18. Unity的Windows游戏转Android平台的114514个坑
  19. USACO入门以及提交格式
  20. 5G三大场景应用及时频资源分配思想

热门文章

  1. 嵌入式环境搭建之ssh
  2. matlab c2d 零阶保持器,计控实验二 连续系统变换为离散系统
  3. word中使用超级链接
  4. java 生成 二维码
  5. 如何从事自己热爱的事情并能赚到体面的薪资
  6. 计算机无法连接苹果手机软件,iphone连接win10电脑后没反应怎么解决
  7. CSU 1507: 超大型LED显示屏(数学)
  8. 皮肤变白方法,四个日常小技巧!
  9. Python文件字节读写
  10. 华为服务器登陆不了系统,服务器的数据库怎么登陆不了怎么办