一道比较好的树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为TV端助力 同时setTag两次,保存多种值

    示例代码: view.setTag(R.string.action_settings,hodler.content); 接收两个值,一个是key值,必须是唯一值,而且要写在values/ids.xml ...

  2. 你不可不知的Java引用类型之——WeakReference源码详解

    定义 WeakReference是弱引用,该引用不会影响垃圾回收器对对象的回收,不会影响对象的生命周期. 说明 当虚拟机在某个时间点决定要回收一个弱可达(weakly-reachable)对象时,会自 ...

  3. c# 建立到数据源的连接 以及获取项目配置文件的属性

    两种连接数据库的写法: <connectionStrings> <add name="HRModelsContainer" connectionString=&q ...

  4. C#核心基础--静态类&部分类

    静态类 用 static 关键字修饰的类叫做静态类,静态类通常用来定义工具类.静态类不能实例化,不能从指定基类继承而来,静态类隐式从 Object 类继承而来.静态类只能包含静态成员和常量,因为常量是 ...

  5. 通过linkserver不能调远程表值函数

    Question: 通过linkserver调远程表值函数报错如下 Solution: 注意:查询语句中的[SDS_NONEDI].[DBO].ddddd(),不能加server名[sdsc2-1]. ...

  6. Python 标示符和关键字

    标示符 开发人员在程序中自定义的一些符号和名称.标示符是自己定义的,如变量名 .函数名等 标示符的规则 标示符由字母.下划线和数字组成,且数字不能开头   注:python中的标识符是区分大小写的 命 ...

  7. This network connection does not exist

    This network connection does not exist 在windows server 2008上面map了一个磁盘,共享的folder被我停止共享后,点击该磁盘的disconn ...

  8. netsh winsock reset命令,作用是重置 Winsock 目录

    Win xp重置 编辑 要为 Windows XP 重置 Winsock,请按照下列步骤操作: 1.单击“开始”,运行中输入cmd. 2.然后输入命令 netsh winsock reset. 3.重 ...

  9. Java教程01-基础语法

    目录 1. 基本概念 1.1. 环境变量 Path环境变量的作用->寻找命令 classpath变量的作用->寻找类文件 1.2. JDK里面有什么? 1.3. 什么是JRE? 2. Ja ...

  10. 028实现strStr()

    #pragma once #include "000库函数.h" /*********************自解**************/ //使用算法中的find 12ms ...