Luogu 4323 [JSOI2016]独特的树叶
新技能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]独特的树叶的更多相关文章
- Luogu P4323 [JSOI2016]独特的树叶
一道比较好的树Hash的题目,提供一种不一样的Hash方法. 首先无根树的同构判断一般的做法只有树Hash,所以不会的同学可以做了Luogu P5043 [模板]树同构([BJOI2015]树的同构) ...
- 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 ...
- P4323 [JSOI2016]独特的树叶(树哈希)
传送门 树哈希?->这里 反正大概就是乱搞--的吧-- //minamoto #include<bits/stdc++.h> #define R register #define l ...
- [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\)同构 ...
随机推荐
- 20165210 Java第一次实验报告
20165210 第一次实验报告 实验内容 建立目录运行简单的Java程序 建立自己学号的目录 在上个目录下建立src,bin等目录 Javac,Java的执行在学号目录下 IDEA的调试与设置断点 ...
- (转)libcurl库使用方法,好长,好详细。
一.ibcurl作为是一个多协议的便于客户端使用的URL传输库,基于C语言,提供C语言的API接口,支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP ...
- SQL使用指南(2)—— 约束的使用
主键约束 (1)创建表时添加主键约束 primary key<column_name> (2) 修改表时添加主键约束 ALTER TABLE table_name ADD CONSTRAI ...
- centos6下搭建gitlab
gitlab安装方法,最新安装方法见官网:https://www.gitlab.com.cn/installation/#centos-6 1.在 Centos 6 系统上, 下面的命令将在系统防火墙 ...
- django的工作图
- JavaWeb框架_Struts2_(二)----->Struts2的核心配置
2. Struts2的核心配置 2.1 配置Struts.xml文件 2.1.1 Struts.xml文件 Struts2框架的核心配置文件是Struts.xml,该文件主要用来配置Action和 ...
- BZOJ2096:[POI2010]Pilots
浅谈队列:https://www.cnblogs.com/AKMer/p/10314965.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?i ...
- Filebeat 5.x 日志收集器 安装和配置
Filebeat 5.x版本 风来了.fox 1.下载和安装 https://www.elastic.co/downloads/beats/filebeat 这里选择 LINUX 64-BIT 即方式 ...
- 通过phpMyAdmin拿webshell
general_log默认为关闭的,root权限开启后,general_log_file会保存所有的查询语句 所以可以开启general_log,然后设置general_log_file为一个php文 ...
- java 多线程系列---JUC原子类(二)之AtomicLong原子类
概要 AtomicInteger, AtomicLong和AtomicBoolean这3个基本类型的原子类的原理和用法相似.本章以AtomicLong对基本类型的原子类进行介绍. AtomicLong ...