Luogu P4323 [JSOI2016]独特的树叶
一道比较好的树Hash的题目,提供一种不一样的Hash方法。
首先无根树的同构判断一般的做法只有树Hash,所以不会的同学可以做了Luogu P5043 【模板】树同构([BJOI2015]树的同构)再来。
首先我们直接考虑一种朴素的想法,暴力求出\(A\)树中以每一个点为根时的Hash值
然后扔到一个set(你要再写个Hash也没事)里,再在\(B\)树中枚举叶子节点,判断去掉这个叶子节点后的Hash值是否在set里即可。
发现这样算法的复杂度瓶颈在求\(A\)树Hash值时的\(O(n^2)\),那么考虑优化。
由于树Hash的原理就是不要让节点编号去影响Hash值,所以可行的Hash方式不止一种。
那么我们考虑一下用异或+子树大小的方式结合Hash的进制规则来做。
具体的说就是定义Hash值\(H_i=\bigoplus_{j\in son_i}H_j \times seed+size_j\),其中\(\bigoplus\)表示异或和。
那么我们只要先求出以某个点为根时的Hash值,然后在递推到每一个点为根的情况即可,这个直接用异或的性质异或回去抵消即可。
那么问题解决,复杂度为\(O(n\log n)\)(别忘了set的复杂度),如果用Hash代替的花是\(O(n)\)的。
CODE
#include<cstdio>
#include<cctype>
#include<set>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
typedef unsigned long long ull;
const int N=100005; const ull seed=1e9+7;
int n; set <ull> s;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
#undef tc
}F;
inline ull updata(CI x,CI y)
{
return x*seed+y;
}
class Tree_Hash_Solver
{
private:
struct edge
{
int to,nxt;
}e[N<<1]; int head[N],cnt,deg[N],size[N],g[N],x,y;
public:
int n,f[N]; //g only in subtree,f include all tree
inline void add(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt; ++deg[x];
}
inline void init(void)
{
for (RI i=1;i<n;++i) F.read(x),F.read(y),add(x,y),add(y,x);
}
#define to e[i].to
inline void DFS1(CI now,CI fa)
{
size[now]=g[now]=1; for (RI i=head[now];i;i=e[i].nxt)
if (to!=fa) DFS1(to,now),size[now]+=size[to],g[now]^=updata(g[to],size[to]);
}
inline void DFS2(CI now,CI fa)
{
if (!fa) f[now]=g[now]; else f[now]=g[now]^updata(f[fa]^updata(g[now],size[now]),n-size[now]);
for (RI i=head[now];i;i=e[i].nxt) if (to!=fa) DFS2(to,now);
}
#undef to
inline bool isleaf(CI now)
{
return deg[now]==1;
}
inline bool check(CI now)
{
return s.count(f[e[head[now]].to]^updata(g[now],1));
}
}A,B;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),A.n=n,A.init(),A.DFS1(1,0),A.DFS2(1,0),i=1;i<=n;++i) s.insert(A.f[i]);
for (B.n=n+1,B.init(),i=1;i<=B.n;++i) if (!B.isleaf(i)) { B.DFS1(i,0); B.DFS2(i,0); break; }
for (i=1;i<=B.n;++i) if (B.isleaf(i)&&B.check(i)) return printf("%d",i),0; return 0;
}
Luogu P4323 [JSOI2016]独特的树叶的更多相关文章
- Luogu 4323 [JSOI2016]独特的树叶
新技能get 树哈希,考虑到两棵树相同的条件,把每一个结点的哈希值和树的siz写进哈希值里去. 做出A树每一个结点为根时的树的哈希值丢进set中,然后暴力枚举B树中度数为1的点,求出删掉这个点之后的哈 ...
- P4323 [JSOI2016]独特的树叶(树哈希)
传送门 树哈希?->这里 反正大概就是乱搞--的吧-- //minamoto #include<bits/stdc++.h> #define R register #define l ...
- BZOJ4754 & 洛谷4323 & LOJ2072:[JSOI2016]独特的树叶——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4754 https://www.luogu.org/problemnew/show/P4323 ht ...
- BZOJ 4754 [JSOI2016]独特的树叶 | 树哈希判同构
题目链接 这道题是一道判断无根树同构的模板题,判断同构主要的思路就是哈希. 一遇到哈希题,一百个人能有一百零一种哈希方式,这篇题解随便选用了一种--类似杨弋<Hash在信息学竞赛中的一类应用&g ...
- bzoj4754[JSOI2016]独特的树叶
这个题....别人写得怎么都....那么短啊? 我怎么....WA了好几次啊....怎么去loj扒了数据才调出来啊? 这个算法...怎么我还是不知道对不对啊 怎么回事啊怎么回事啊怎么回事啊? 请无视上 ...
- BZOJ4754 JSOI2016独特的树叶(哈希)
判断两棵无根树是否同构只需要把重心提作根哈希即可.由于只添加了一个叶子,重心的位置几乎不发生偏移,所以直接把两棵树的重心提起来,逐层找哈希值不同且对应的两子树即可.被一个普及组子问题卡一年. #inc ...
- [JSOI2016]独特的树叶
https://zybuluo.com/ysner/note/1177340 题面 有一颗大小为\(n\)的树\(A\),现加上一个节点并打乱编号,形成树\(B\),询问加上的节点最后编号是多少? \ ...
- bzoj 4754: [Jsoi2016]独特的树叶
不得不说这是神题. %%% http://blog.csdn.net/samjia2000/article/details/51762811 #include <cstdio> #in ...
- 【BZOJ4754】独特的树叶(哈希)
[BZOJ4754]独特的树叶(哈希) 题面 BZOJ 给定一个\(n\)个节点的树A和一个\(n+1\)个节点的树\(B\) 求\(B\)的一个编号最小的节点,使得删去这个节点后\(A,B\)同构 ...
随机推荐
- 「Android」 Surface分析
本篇针对Surface模块进行分析,从Java层的Activity创建开始,到ViewRoot.WindowsManagerService,再到JNI层和Native层. 首先推荐一个Android源 ...
- 从头开始:详解MVVM、MVVMLight
究竟为什么要学习MVVM? 相信大部分同学在刚开始接触MVVM的时候(包括我自己),心里默默在想这究竟是什么玩意?一个简单的功能要写一大段代码才能完成,在看到MVVM的核心目标: 1.让UI界面与逻辑 ...
- javascript:正则表达式、一个表单验证的例子
本文内容: 正则表达式 正则表达式的使用方法 正则表达式的特殊匹配字符 正则表达式修饰符 利用正则表达式进行表单验证的例子 首发日期:2018-05-13 正则表达式: 正则表达式的使用方法: 首先创 ...
- Java:注解Annotation(元数据)
本文内容: 注解Annotation的介绍 基本注解的用法 自定义注解 首发日期:2018-07-28 注解Annotation的介绍 Annotation是代码中的特殊标记,能够在编译.类加载.运行 ...
- thread/threading——Python多线程入门笔记
1 什么是线程? (1)线程不同于程序. 线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制: 多线程类似于同时执行多个不同程序. (2)线程不同于进程. 每个独立的进程有一个程 ...
- mac 全角/半角标点符号切换
快捷键:option+shift+H 背景是这样的,前段时间sublimeText新装了HTML/CSS/JS Prittify,JS代码格式化的快捷键是:command+shift+H. 记性有点差 ...
- 洗礼灵魂,修炼python(66)--爬虫篇—BeauitifulSoup进阶之“我让你忘记那个负心汉,有我就够了”
说明一下,这个标题可能有点突兀,结合上一篇一起看就行 前面已经对BeautifulSoup有了了解了,相信你基本已经学会怎么获取网页数据了,那么BeautifulSoup这么吊,还有没有其他的功能呢? ...
- SQL SERVER查询字段在哪个表里
); SET @ColumnName='字段名的模糊匹配'; SELECT 表名=D.NAME, 表说明 THEN ISNULL(F.VALUE, ' ') ELSE ' ' END, 字段序号 = ...
- SQL Server 锁机制
锁兼容性图: 一.锁的粒度: 比较需要注意的是RID/KEY.HoBT/PAGE这两对儿的区别,RID和HoBT是针对堆表的,即没有聚集索引的表. 二.锁的模式: 1.关于其中的S.U.X锁: 共享锁 ...
- Python3 读写文件
读文件 打开一个文件用open()方法(open()返回一个文件对象): >>> f = open(filename, mode,buffering) #buffering寄存,具体 ...