#238 蔡老板分果子 [哈希 or DFS序]

题目描述

春天来了,万物复苏,动物们又到了发情的季节。蔡老板终于下定决心砍下了自家后院的两棵果树,并决定和自己喜欢的人一起分享果树上的果子。

这两棵果树一棵是长生果树另一棵是人参果树,两棵树上都有 nnn 个果子,编号为 1∼n" role="presentation" style="position: relative;">1∼n1∼n1∼n,并分别由 n−1n−1n−1 段树枝连接起来。 为了把果子分成两份,蔡老板决定再两棵树上各砍一刀,分别砍断一根树枝把两棵树上的果子各分成两个部分。之后,对于每一棵果树,蔡老板会选择 111 号果子所在的那一部分。显然这样分果子一共有(n−1)2" role="presentation" style="position: relative;">(n−1)2(n−1)2 (n−1)^2种分法,而蔡老板想知道,有多少种切割方法,使得蔡老师拿到的长生果和人参果具有相同的标号集合。

输入格式

第一行一个正整数 nnn 表示两棵树的大小。

接下来 n−1" role="presentation" style="position: relative;">n−1n−1n−1行每行两个正整数表示长生果树上的边。

接下来 n−1n−1n−1 行每行两个正整数表示人参果树上的边。

输出格式

输出一行一个正整数表示蔡老板关心的切割方法的数目。

题解

非常讨厌搬运带有LaTeXLaTeXLaTeX公式的题目 ̄へ ̄

题目大意就是求有多少棵含有相同编号的子树。

1 暴力 43分

有一个很显然的暴力做法就是:枚举两棵树的每一条边,搜索判断边两边的树是否相同。代码还是很好写(虽然我写炸了),就不贴了。

2 正解

2.1 哈希 随机化算法

这道题卡哈希,xor哈希还得双蛤;还卡时间,map都不行,必须用unordered_map。

哈希的基本思路就是用一个数来表示一棵树的形态(这里的形态并不是形状相同,而是这棵树里包含了哪些数)。

树上的边都是无向边,[u,v][u,v][u,v]和[v,u][v,u][v,u]是等价的。因此选择的哈希必须要满足交换律。满足交换律的三种运算分别是:加法,乘法,异或。但是加法和乘法并不很可靠,比如对于加法,由 3和5构成的树 和由 2和6构成的树 会被认为是同一棵树;乘法同理。但是异或相对可靠,因为如果两棵子树相同,那么两棵子树对应的哈希值的每一个二进制位都要一一对应,因此错误的几率就会大大减小。

一定要双蛤!哈希要用unsigned long long!

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<unordered_map>
#define N 200010
using namespace std;
int Last1[N<<1],Next1[N<<1],End1[N<<1],cnt1;
int Last2[N<<1],Next2[N<<1],End2[N<<1],cnt2;
unsigned long long Mat1[N],Mat2[N],Hash1[N],Hash2[N],Hash11[N],Hash22[N];
unordered_map<unsigned long long,bool>Mark,Markk;
void Ins1(int x,int y){End1[++cnt1]=y,Next1[cnt1]=Last1[x],Last1[x]=cnt1;
}
void Ins2(int x,int y){End2[++cnt2]=y,Next2[cnt2]=Last2[x],Last2[x]=cnt2;
}
void DFS1(int u,int fa){Hash1[u]=Mat1[u],Hash11[u]=Mat2[u];for(int i=Last1[u];i;i=Next1[i]){int v=End1[i];if(v==fa)continue;DFS1(v,u);Hash1[u]^=Hash1[v],Hash11[u]^=Hash11[v];}
}
void DFS2(int u,int fa){Hash2[u]=Mat1[u],Hash22[u]=Mat2[u];for(int i=Last2[u];i;i=Next2[i]){int v=End2[i];if(v==fa)continue;DFS2(v,u);Hash2[u]^=Hash2[v],Hash22[u]^=Hash22[v];}
}
int main(){srand(73939133);int n,Ans=0;scanf("%d",&n);for(int i=1;i<=n;i++){ //使得随机数更加随机Mat1[i]=rand()*(rand()+i)+rand()%31;Mat2[i]=rand()*(rand()+i)+rand()%31; } for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);Ins1(u,v),Ins1(v,u);}for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);Ins2(u,v),Ins2(v,u);}DFS1(1,0);DFS2(1,0);for(int i=2;i<=n;i++){//从以1为根的树中去掉以i为根的子树//Mark[i],Markk[i]均表示存在i形态的子树Mark[Hash1[1]^Hash1[i]]=true;Markk[Hash11[1]^Hash11[i]]=true;}for(int i=2;i<=n;i++)if(Mark[Hash2[1]^Hash2[i]])if(Markk[Hash22[1]^Hash22[i]])Ans++;printf("%d",Ans);return 0;
}

2.2 DFS序 确定性算法

如果我们要判断两个序列AAA和B" role="presentation" style="position: relative;">BBB中有多少相等的子串,可以先把AAA序列中的数字按照下标的顺序依次标号,再把B" role="presentation" style="position: relative;">BBB序列中的数字对应标号(这种方法的使用前提是AAA序列中的数字互不相同,B" role="presentation" style="position: relative;">BBB序列中的数字可以有重复),看BBB序列中有多哪些部分的标号是连续的。

比如:

B" role="presentation" style="position: relative;">BBB序列的标号中,标红部分的数字是连续的,那么就说明这一部分在AAA序列中也是出现过的。

以上是在序列中的做法,在树中同样如此。我们先把A" role="presentation" style="position: relative;">AAA树跑一遍DFSDFSDFS,让每个点都有一个DFSDFSDFS序(树上的每个节点编号显然是不同的),再把这个DFSDFSDFS序映射到BBB树上。如果B" role="presentation" style="position: relative;">BBB树中的某一棵子树有连续的编号,那么这棵子树在AA<script type="math/tex" id="MathJax-Element-29">A</script>中也出现过。

上图中,圈内的数字是B树中每个节点的编号,圈旁的数字是对应数字在A树中的DFS序。以2为根的子树中,新编号是连续的,为[2,5],所以这棵子树在A树中出现过;但是以3为根的子树的新编号不连续,所以就没有出现过。

这种做法显然更加优秀,代码也好写。用时更少,空间更小。

↑这是哈希做法

↑这是DFS序做法

#include<iostream>
#include<cstdio>
#define N 200100
using namespace std;
struct node{int l,r;}Ran[N];
int NewID[N],Size1[N],Size2[N],OldID[N],Time,Ans;
int End1[N<<1],Next1[N<<1],Last1[N<<1],cnt1;
int End2[N<<1],Next2[N<<1],Last2[N<<1],cnt2;
void DFS1(int u,int fa){NewID[u]=++Time,Size1[u]=1,OldID[Time]=u;for(int i=Last1[u];i;i=Next1[i]){int v=End1[i];if(v==fa)continue;DFS1(v,u);Size1[u]+=Size1[v];}
}
void DFS2(int u,int fa){Size2[u]=1;for(int i=Last2[u];i;i=Next2[i]){int v=End2[i];if(v==fa)continue;DFS2(v,u);Size2[u]+=Size2[v];}
}
void DFS3(int u,int fa){//我记录的是以u为根的子树中新编号的最小最大值//当 编号的范围==子树大小,那么这段编号就是连续的Ran[u].l=NewID[u],Ran[u].r=NewID[u];for(int i=Last2[u];i;i=Next2[i]){int v=End2[i];if(v==fa)continue;DFS3(v,u);Ran[u].l=min(Ran[u].l,Ran[v].l);Ran[u].r=max(Ran[u].r,Ran[v].r);}if(u!=1 && Ran[u].r-Ran[u].l+1==Size2[u])if(Size1[OldID[Ran[u].l]]==Size2[u])Ans++;
}
void Ins1(int x,int y){End1[++cnt1]=y,Next1[cnt1]=Last1[x],Last1[x]=cnt1;
}
void Ins2(int x,int y){End2[++cnt2]=y,Next2[cnt2]=Last2[x],Last2[x]=cnt2;
}
int main(){
//  freopen("ex_a3.in","r",stdin);int n;scanf("%d",&n);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);Ins1(u,v),Ins1(v,u);}for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);Ins2(u,v),Ins2(v,u);}DFS1(1,0);DFS2(1,0);DFS3(1,0);printf("%d",Ans);return 0;
}

#238 蔡老板分果子 [哈希 or DFS序]相关推荐

  1. 哈希/图论-蔡老板分果子

    #238. 蔡老板分果子 统计 描述 提交 自定义测试 春天来了,万物复苏,动物们又到了发情的季节.蔡老板终于下定决心砍下了自家后院的两棵果树,并决定和自己喜欢的人一起分享果树上的果子. 这两棵果树一 ...

  2. 1549: 蔡老板发工资

    描述 题目描述: 蔡老板身为NEUQ-ACM的BOSS,当然不用事必躬亲,所以要靠俱乐部勤劳的小伙伴(dalao)替老板做些工作.但是贤明的蔡老板是会给俱乐部的小伙伴们发工资的(^_^),工作的天数越 ...

  3. 图灵杯 蔡老板的会议

    题目描述 图灵杯个人赛就要开始了,蔡老板召集俱乐部各部门的部长开会.综合楼有N (1<=N<=1000)间办公室,编号1~N每个办公室有一个部长在工(mo)作(yu),其中X号是蔡老板的办 ...

  4. NEUQ图灵杯之A题——蔡老板的会议

    题目意思很简单,就是求最短路,但是,路径是单向的,所以要正着dij一遍,反着dij一遍,再求两次和的最大值,也可以创建两个图,这样,只要对两个图分别dij一遍一次,就不要写两个dij函数了,普通dij ...

  5. Contest1065 - 第四届“图灵杯”NEUQ-ACM程序设计竞赛(个人赛)A蔡老板的会议

    题目描述 图灵杯个人赛就要开始了,蔡老板召集俱乐部各部门的部长开会.综合楼有N (1<=N<=1000)间办公室,编号1~N每个办公室有一个部长在工(mo)作(yu),其中X号是蔡老板的办 ...

  6. PTA 7-15(查找) 航空公司VIP客户查询(25 分) 25分代码 哈希方法

    本来用map 写的,死活超时,看来卡不过去 只能哈希了 这里还稍微优化了一下,其实每个 哈希后的值存个 vector 来表示他的原值也行 (注: 博客作为交流使用,请勿抄袭应付作业) // #incl ...

  7. L2-039 清点代码库 (25 分)(哈希)

    上图转自新浪微博:"阿里代码库有几亿行代码,但其中有很多功能重复的代码,比如单单快排就被重写了几百遍.请设计一个程序,能够将代码库中所有功能重复的代码找出.各位大佬有啥想法,我当时就懵了,然 ...

  8. 计算机网络 | 网络基础 :网络协议,协议分层,数据封装与分用,地址管理,字节序

    目录 网络协议 网络协议的概念 网络协议的组成 协议分层 OSI七层模型 TCP/IP五层模型(四层模型) 数据封装与分用 封装 分用 地址管理 IP地址与端口 MAC地址 网络字节序与主机字节序 网 ...

  9. 1130 Infix Expression (25 分)【难度: 一般 / 知识点: 中序遍历】

    https://pintia.cn/problem-sets/994805342720868352/problems/994805347921805312 通过入度0找到根节点,然后中序遍历. #in ...

最新文章

  1. 科学研究发现,盲人用时间感知空间
  2. redis入门系列(一)redis安装部署
  3. mybatis 中case_mybatis 对string类型判断比较 group case when then 综合
  4. CentOS7中使用Docker安装SVN以及配置账号权限
  5. Python 基本数据类型 (一) - 整数
  6. python递归排序组合_如何用Python求list的排列组合:一种递归方式
  7. hdu 1421 动态规划
  8. 使用ABAP事务码STAD分析Asynchronous RFC call性能
  9. KnockoutJS + My97DatePicker
  10. BUUOJ reverse 刮开有奖
  11. c# c均值聚类及DBSCAN聚类
  12. mysql xtrabackup 保护模式_MySQL Xtrabackup备份原理和实现细节
  13. ​技术沙龙 | 移动云Teatalk(西安站)带你走进云网融合
  14. JAVA虚拟机——利用javap反编译class文件分析代码执行过程
  15. proc文件系统实现用户空间与内核空间的数据通信
  16. 用txt写的mysql数据库_TXT怎么导入mySQL数据库
  17. 10个免费网络管理工具
  18. 新兴科技成果——越穷越要云计算
  19. [机缘参悟-6]:阳明心学三大核心思想:心外无物、知行合一、致良知的理解
  20. 企业级shel高级l常用命令

热门文章

  1. 腾讯是如何做Unity手游性能优化的
  2. 公开资料整理网是什么_语文老师最常用的5个备课网站推荐,第1个资料质量很高...
  3. TimeWheel时间轮算法原理及实现(附源码)
  4. 美国OFAC发布针对个人的“网络安全相关处罚”规则
  5. adams 两角之差测量 平动转动物体角度测量
  6. 关于刚安装的新系统的一些设置
  7. N76E003合并boot和app
  8. 【论文阅读笔记】Automatic Liver and Lesion Segmentation in CT Using Cascaded Fully Convolutional Neural Net
  9. 苹果付费app共享公众号_【苹果付费APP共享】 Affinity Photo
  10. Arduino 按键传感器检测实验带原理图说明