一道比较好的树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]独特的树叶的更多相关文章

  1. Luogu 4323 [JSOI2016]独特的树叶

    新技能get 树哈希,考虑到两棵树相同的条件,把每一个结点的哈希值和树的siz写进哈希值里去. 做出A树每一个结点为根时的树的哈希值丢进set中,然后暴力枚举B树中度数为1的点,求出删掉这个点之后的哈 ...

  2. P4323 [JSOI2016]独特的树叶(树哈希)

    传送门 树哈希?->这里 反正大概就是乱搞--的吧-- //minamoto #include<bits/stdc++.h> #define R register #define l ...

  3. BZOJ4754 & 洛谷4323 & LOJ2072:[JSOI2016]独特的树叶——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4754 https://www.luogu.org/problemnew/show/P4323 ht ...

  4. BZOJ 4754 [JSOI2016]独特的树叶 | 树哈希判同构

    题目链接 这道题是一道判断无根树同构的模板题,判断同构主要的思路就是哈希. 一遇到哈希题,一百个人能有一百零一种哈希方式,这篇题解随便选用了一种--类似杨弋<Hash在信息学竞赛中的一类应用&g ...

  5. bzoj4754[JSOI2016]独特的树叶

    这个题....别人写得怎么都....那么短啊? 我怎么....WA了好几次啊....怎么去loj扒了数据才调出来啊? 这个算法...怎么我还是不知道对不对啊 怎么回事啊怎么回事啊怎么回事啊? 请无视上 ...

  6. BZOJ4754 JSOI2016独特的树叶(哈希)

    判断两棵无根树是否同构只需要把重心提作根哈希即可.由于只添加了一个叶子,重心的位置几乎不发生偏移,所以直接把两棵树的重心提起来,逐层找哈希值不同且对应的两子树即可.被一个普及组子问题卡一年. #inc ...

  7. [JSOI2016]独特的树叶

    https://zybuluo.com/ysner/note/1177340 题面 有一颗大小为\(n\)的树\(A\),现加上一个节点并打乱编号,形成树\(B\),询问加上的节点最后编号是多少? \ ...

  8. bzoj 4754: [Jsoi2016]独特的树叶

    不得不说这是神题. %%%   http://blog.csdn.net/samjia2000/article/details/51762811 #include <cstdio> #in ...

  9. 【BZOJ4754】独特的树叶(哈希)

    [BZOJ4754]独特的树叶(哈希) 题面 BZOJ 给定一个\(n\)个节点的树A和一个\(n+1\)个节点的树\(B\) 求\(B\)的一个编号最小的节点,使得删去这个节点后\(A,B\)同构 ...

随机推荐

  1. Android样式主题及自定义属性

    一.Selector——图形.颜色选择器 语法 <selector>   <item android:drawable=“drawableResA” android:state_xx ...

  2. 添加/删除/修改Windows 7右键的“打开方式”

    右键菜单添加/删除"打开方式" 此"打开方式"非系统的"打开方式",二者可以并存. 右键菜单添加"打开方式" 在HKEY ...

  3. (转载)解决NVIDIA显卡驱动“没有找到兼容的图形硬件”的问题

    (转载)解决NVIDIA显卡驱动“没有找到兼容的图形硬件”的问题 原出处:http://www.cnblogs.com/longdouhzt/archive/2012/02/28/2370660.ht ...

  4. nginx的rewrite ,如何在flask项目中获取重写前的url

    1. 在flask配一个重写到哪的路由,假设是/rewite/,然后到nginx的配置文件写重写规则,我这里重写全部的请求,接着测试能否重写成功 1. 添加一个路由 配置重写规则 测试成功 2.接下来 ...

  5. selenium驱动程序下载和使用流程

    转自https://blog.csdn.net/weixin_42660771/article/details/81286982 1.下载地址    https://github.com/mozill ...

  6. Dapp已来,如何把握区块链创富模式变化的趋势

    区块链技术持续升温,Dapp迅速成为焦点,未来区块链市场上新的蓝海.这么说当然不是空想出来的,而是从区块链市场的发展趋势中推断而来.区块链市场由最初的挖矿炒币到如今尝试投入行业应用,随着技术和应用模式 ...

  7. AspNet mvc的一个bug

    [HttpPost] public ActionResult updateLoan(TuWenMilitaryRank entity) 使用mvc绑定表单 每次绑定的对象都为null,查看Reques ...

  8. 5. svg学习笔记-坐标系变换

    之前我们编写图形元素的时候,编写好了位置大小就是固定的,通过坐标系变换,可以移动缩放,旋转图形,但必须声明的是,进行变换时是图形相对于坐标系的变化,就是图形是不发生变化的,而是坐标系发生了变化,比如缩 ...

  9. Unittest框架小结

    在日常的自动化测试过程中,Python里有一个自带的单元测试框架是unittest模块,简单易用,这里简单介绍下其主要的用法. Unittest测试框架主要包含四个部分 TestCase 也就是测试用 ...

  10. 为什么zookeeper集群中节点配置个数是奇数个?

    Zookeeper的大部分操作都是通过选举产生的.比如,标记一个写是否成功是要在超过一半节点发送写请求成功时才认为有效.同样,Zookeeper选择领导者节点也是在超过一半节点同意时才有效.最后,Zo ...