一道比较好的树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. Future FutrueTask Callable类源码说明以及原理使用

    1.Future Callable FutureTask 源码说明 JDK内置的Future主要使用到了Callable接口和FutureTask类. Callable是类似于Runnable的接口, ...

  2. Android为TV端助力 自定义activity

    今天公司有个需要需要自动弹出界面,而dialog又不符合要求,所以自定义的一个activity的样式 首先在androidmainfest.xml上注册你的activity <activity ...

  3. 性能优化7--App瘦身

    1. 前言 如果你对App优化比较敏感,那么Apk安装包的大小就一定不会忽视.关于瘦身的原因,大概有以下几个方面: 对于用户来说,在功能差别不大的前提下,更小的Apk大小意味更少的流量消耗,也意味着更 ...

  4. 关于正餐智能POS6.0.1.1改版后,订单模块无法进行部分退款的FAQ

    适用版本:智能POS正餐V6.0.1.1+ 适用情况:订单模块,无法输入自定义金额进行部分退款. 原因:为让报表统计的数据更准确. 改版之后仍可适用部分退款的情况: 1.口碑先付订单,可在口碑模块,选 ...

  5. SQL 中常用存储过程xp_cmdshell运行cmd命令

    目的: 使用SQL语句,在D盘创建一个文件夹myfile 首先查询系统配置 SELECT * FROM sys.configurations WHERE name='xp_cmdshell' OR n ...

  6. java POI导出Excel文件数据库的数据

    在web开发中,有一个经典的功能,就是数据的导入导出.特别是数据的导出,在生产管理或者财务系统中用的非常普遍,因为这些系统经常要做一些报表打印的工作.这里我简单实现导出Excel文件. POI jar ...

  7. sql server 计算两个时间 相差的 几天几时几分几秒

    CAST ( CAST ( DATEDIFF ( ss, StartTime, ConcludeTime ) / ( 60 * 60 * 24 ) AS INT ) AS VARCHAR ) + '天 ...

  8. forfiles删除过期文件robocopy

    forfiles /p "F:\SDSC16B" /s /m *.bak /d -20 /c "cmd /c del @FILE" /p:指定目录 /s:递归搜 ...

  9. MongoDB启动文件配置参数详解

    接手的MongoDB只有一个日志文件,体积非常大,排错不便.在找解决办法的时候发现MongoDB的启动文件配置项超级多,于是产生了解释配置参数的想法. mongod服务有两种启动方式 一种是通过配置文 ...

  10. Python 输出格式符号

    Python 常见的输出格式符号