新技能get

树哈希,考虑到两棵树相同的条件,把每一个结点的哈希值和树的siz写进哈希值里去。

做出A树每一个结点为根时的树的哈希值丢进set中,然后暴力枚举B树中度数为1的点,求出删掉这个点之后的哈希值是否相同。

暴力算哈希是$O(n^{2})$的,考虑换根法,一个点作根的时候它的子树中的信息是不会变的,唯一的改变就是它的父亲及往上变成了它的新的一棵子树,这样我们可以递推出每一个结点的父亲作它的子树时的哈希值。

所以先自下到上哈希一遍,再重新自上到下算一遍,算父亲作儿子的哈希值就相当于挖掉一个子树,具体可以看代码实现。

因为哈希过程中的$sort$,时间复杂度为近似的$O(nlogn)$

感觉你谷评分好乱

Code:

#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ull; const int N = 1e5 + ;
const ull sed = ; int m;
ull q2[N], bin[N];
set <ull> s; struct Node {
int now;
ull val; Node (int x = , ull y = ) : now(x), val(y) {} friend bool operator < (const Node &u, const Node &v) {
return u.val < v.val;
} } q1[N]; inline void read(int &X) {
X = ;
char ch = ;
int op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} struct Tree {
int n, tot, head[N], fa[N], siz[N], deg[N];
ull v[N], f[N], rt[N], suf[N], pri[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} inline void addEdge(int x, int y) {
deg[x]++, deg[y]++;
add(x, y), add(y, x);
} inline void init(int now) {
n = now, tot = fa[] = ;
for(int i = ; i <= n; i++)
head[i] = deg[i] = ;
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
addEdge(x, y);
}
} void dfs1(int x) {
siz[x] = ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x]) continue;
fa[y] = x;
dfs1(y);
siz[x] += siz[y];
} int cnt = ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x]) continue;
q2[++cnt] = v[y];
} sort(q2 + , q2 + cnt + );
v[x] = ;
for(int i = ; i <= cnt; i++)
v[x] = v[x] * sed + q2[i];
v[x] = v[x] * sed + (ull)siz[x];
} void dfs2(int x) {
int cnt = ;
if(x > ) q1[++cnt] = Node(fa[x], f[x]);
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x]) continue;
q1[++cnt] = Node(y, v[y]);
} sort(q1 + , q1 + cnt + );
pri[] = ;
for(int i = ; i <= cnt; i++)
pri[i] = pri[i - ] * sed + q1[i].val;
suf[cnt + ] = ;
for(int i = cnt; i >= ; i--)
suf[i] = suf[i + ] + q1[i].val * bin[cnt - i]; for(int i = ; i <= cnt; i++) {
if(q1[i].now == fa[x]) continue;
f[q1[i].now] = pri[i - ] * bin[cnt - i] + suf[i + ];
f[q1[i].now] = f[q1[i].now] * sed + (ull)(n - siz[q1[i].now]);
} for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x]) continue;
dfs2(y);
}
} void calc() {
dfs1(), dfs2();
for(int x = ; x <= n; x++) {
int cnt = ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x]) continue;
q2[++cnt] = v[y];
}
if(x != ) q2[++cnt] = f[x]; sort(q2 + , q2 + + cnt);
rt[x] = ;
for(int i = ; i <= cnt; i++)
rt[x] = rt[x] * sed + q2[i];
rt[x] = rt[x] * sed + (ull)n;
}
} } a, b; int main() {
read(m); bin[] = ;
for(int i = ; i <= m + ; i++)
bin[i] = bin[i - ] * sed; a.init(m), a.calc();
b.init(m + ), b.calc(); /* for(int i = 1; i <= m; i++)
printf("%llu ", a.rt[i]);
printf("\n"); */ for(int i = ; i <= m; i++)
s.insert(a.rt[i]); for(int i = ; i <= m + ; i++) {
if(b.deg[i] != ) continue;
if((i != && s.find(b.f[i]) != s.end())
|| (i == && s.find(b.v[b.e[b.head[]].to]) != s.end()))
return printf("%d\n", i), ;
} return ;
}

Luogu 4323 [JSOI2016]独特的树叶的更多相关文章

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

    一道比较好的树Hash的题目,提供一种不一样的Hash方法. 首先无根树的同构判断一般的做法只有树Hash,所以不会的同学可以做了Luogu P5043 [模板]树同构([BJOI2015]树的同构) ...

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

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

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

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

  4. bzoj4754[JSOI2016]独特的树叶

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

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

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

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

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

  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. 2018.8.10 programming bat based on python

    @echo off REM Current DevProg Version. Match the pip package version (x.y.z)SET currentversion=0.4.0 ...

  2. Mat ,IplImage, CvMat 之间的转换的总结

    在新版本与旧版本之间纠结,到底是用Mat,还是Iplimage? Mat 侧重于数据计算,而Iplimage注重于图像的处理. 因此,应根据具体需要灵活使用,那个好用用哪个,只要在两者之间进行转换即可 ...

  3. java web service 上传下载文件

    1.新建动态web工程youmeFileServer,新建包com,里面新建类FileProgress package com; import java.io.FileInputStream; imp ...

  4. python 类的定义和继承

    python 2 中类 一.类定义: ? 1 2 class <类名>:   <语句> 类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性如果直接使用类 ...

  5. SQL夯实基础(四):子查询及sql优化案例

    首先我们先明确一下sql语句的执行顺序,如下有前至后执行: (1)from  (2) on   (3) join  (4) where  (5)group by  (6) avg,sum...  (7 ...

  6. Http请求状态码

    1xx - 信息提示   这些状态代码表示临时的响应.客户端在收到常规响应之前,应准备接收一个或多个 1xx 响应.    ·0 - 本地响应成功.   · 100 - Continue 初始的请求已 ...

  7. bzoj 3771 Triple——FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3771 把方案作为系数.值作为指数,两项相乘就是系数相乘.指数相加,符合意义. 考虑去重.先自 ...

  8. HDU3887(树dfs序列+树状数组)

    Counting Offspring Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...

  9. Sass和Less、Stylus的转译和语法(1)

    四.Sass.LESS和Stylus转译成CSSSass.LESS和Stylus源文件(除了LESS源文件在客户端下运行之外)都不能直接被浏览器直接识别,这样一来,要正常的使用这些源文 件,就需要将其 ...

  10. 开发环境入门 linux基础 (部分)正则表达式 grep sed

    /etc/profile /etc/bashrc  .变量添加到shell环境中,永久生效. /root/.bashrc /root/.bash_profile 正则表达式 定义:正则就是用一些具有特 ...