BZOJ4754 & 洛谷4323 & LOJ2072:[JSOI2016]独特的树叶——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4754
https://www.luogu.org/problemnew/show/P4323
JYY有两棵树A和B:树A有N个点,编号为1到N;树B有N+1个点,编号为1到N+1。JYY知道树B恰好是由树A加上一个叶节点,然后将节点的编号打乱后得到的。他想知道,这个多余的叶子到底是树B中的哪一个叶节点呢?
树同构问题基本都是树哈希做的。
参考+copycat:https://www.cnblogs.com/RabbitHu/p/9165770.html
这题也没啥方便的写法了,代码写起来有股重工业的气息,所以本题题解也就是归纳思路,拾人牙慧了。
有一个很简单的方法找到这个结点:枚举B的每个叶子,求这个树删掉这个叶子的哈希值,再与A所有哈希值匹配,如果匹配成功的话就说明这个叶子是合法解,复杂度O(nlogn)
但是很不幸,利用BZOJ4337:[BJOI2015]树的同构的方法求每个根的哈希值的话是O(n^2)的,所以我们需要将其优化到O(nlogn)
(注意,为了方便后期修改值,令f[u]表示u子树的哈希值,f[u]=size[u]*π(f[v]*B^k)和我原本做法不同还请注意。)
第一遍求以1为根的哈希显然不能变,关键就是动态换根了。
画一下图的话就能发现当根节点从fa[u]转到u的时候,只有f[u]和f[fa[u]]发生了变化,设g[u]=此时的f[fa[u]]。
可知g[u]就是f[fa[u]]加了一棵以fa[fa[u]]为根的子树,减了一棵以u为根的子树后的哈希值,我们大可以将所有的子树预处理出来,维护前缀乘积和后缀乘积,然后根据u的不同删掉子树id,则答案为前缀[id-1]*B^k+后缀[id+1](k的值请读者自行讨论)。
这样我们二分查找id,复杂度变成了O(nlogn)可以通过本题。
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
const int N=1e5+;
const ll B=;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int to,nxt;
}e[N*];
int n,cnt,head[N],sz[N],fa[N],ind[N];
ll f[N],g[N],qpow[N];
vector<ll>num[N],nl[N],nr[N];
set<ll>vis;
inline void add(int u,int v){
e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
ll dfs1(int u){
f[u]=;sz[u]=;
num[u].clear();
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[u])continue;
fa[v]=u;num[u].push_back(dfs1(v));sz[u]+=sz[v];
}
if(num[u].empty())return f[u]=;
sort(num[u].begin(),num[u].end());
for(int i=;i<num[u].size();i++)f[u]=f[u]*B+num[u][i];
return f[u]*=sz[u];
}
int ans;
void dfs2(int u,int p){
if(fa[u]){
num[u].push_back(g[u]);
sort(num[u].begin(),num[u].end());
}
int numsz=num[u].size();
nl[u].resize(numsz),nr[u].resize(numsz);
nl[u][]=num[u][];nr[u][numsz-]=num[u][numsz-];
for(int i=;i<numsz;i++)nl[u][i]=nl[u][i-]*B+num[u][i];
for(int i=numsz-;i>=;i--)nr[u][i]=nr[u][i+]+num[u][i]*qpow[numsz-i-];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[u])continue;
if(numsz==){g[v]=;dfs2(v,p);break;}
int id=lower_bound(num[u].begin(),num[u].end(),f[v])-num[u].begin();
g[v]=;
if(id+<numsz)g[v]=nr[u][id+];
if(id->=)g[v]+=nl[u][id-]*qpow[numsz-id-];
g[v]*=(n-sz[v]); if(p&&ind[v]==&&vis.find(g[v])!=vis.end())ans=min(ans,v);
dfs2(v,p);
}
if(!p)vis.insert(nl[u][numsz-]*n);
}
int main(){
n=read();
qpow[]=;
for(int i=;i<=n;i++)qpow[i]=qpow[i-]*B;
for(int i=;i<n;i++){
int u=read(),v=read();
add(u,v);add(v,u);
}
dfs1();dfs2(,);
cnt=;memset(head,,sizeof(head));n++;
for(int i=;i<n;i++){
int u=read(),v=read();
add(u,v);add(v,u);ind[u]++;ind[v]++;
}
dfs1();
ans=N;
if(ind[]==&&vis.find(f[e[head[]].to])!=vis.end())ans=;
dfs2(,);
printf("%d\n",ans);
return ;
}
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
BZOJ4754 & 洛谷4323 & LOJ2072:[JSOI2016]独特的树叶——题解的更多相关文章
- 洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心)
洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/132 ...
- 洛谷P3387 【模板】缩点 题解
背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...
- [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)
[NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...
- [洛谷P1029]最大公约数与最小公倍数问题 题解(辗转相除法求GCD)
[洛谷P1029]最大公约数与最小公倍数问题 Description 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P, ...
- BZOJ5288 & 洛谷4436 & LOJ2508:[HNOI/AHOI2018]游戏——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5288 https://www.luogu.org/problemnew/show/P4436 ht ...
- BZOJ4943 & 洛谷3823 & UOJ315:[NOI2017]蚯蚓排队——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4943 http://uoj.ac/problem/315 https://www.luogu.or ...
- BZOJ1229 & 洛谷2917:[USACO2008 NOV]toy 玩具 & 洛谷4480:[BJWC2018]餐巾计划问题——题解
标题很长emmm…… [USACO2008 NOV]toy 玩具 https://www.luogu.org/problemnew/show/P2917 https://www.lydsy.com/J ...
- BZOJ3675 & 洛谷3648 & UOJ104:[Apio2014]序列分割——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3675 https://www.luogu.org/problemnew/show/P3648 ht ...
- 洛谷3258:[USACO2012 MAR]Flowerpot 花盆——题解
https://www.luogu.org/problemnew/show/P2698#sub 老板需要你帮忙浇花.给出N滴水的坐标,y表示水滴的高度,x表示它下落到x轴的位置. 每滴水以每秒1个单位 ...
随机推荐
- Mybatis JPA 插件简介
前段时间了解到Spring JPA,感觉挺好用,但其依赖于Hibernate,本人看到Hibernate就头大(不是说Hibernate不好哈,而是进阶太难),于是做了一个迷你版的Mybatis JP ...
- Java+Selenium 3.x 实现Web自动化 - 1.自动化准备
(一)自动化准备 说明:本文主要记录了基于公司现有项目(一个电子商务平台),从0开始实现UI自动化的历程.从准备阶段,部分内容直接省略了基础知识,一切以最终做成自动化项目为目标,难免会有晦涩之处.文章 ...
- 怎样从Java转换到Kotlin代码:现在就开始使用Kotlin(KAD 29)
作者:Antonio Leiva 时间:Jul, 4, 2017 原文链接:https://antonioleiva.com/kotlin-from-java/ Kotlin最神奇特性之一是它能与Ja ...
- 聊聊Bug引发事故该不该追求责任
最近读极客时间朱赟的一篇文章有感,在这也聊一下,在互联网的公司大多数以迭代的方式上线需求,节奏一般都比较快,经常会一个需求当天来了第二天就上线,开发和测试时间总共就两天,中间还穿插着别的需求测试,不像 ...
- MATLAB实现连续周期信号的频谱分析(正余弦波信号举例)
关于MATLAB实现连续信号的频谱分析,以正余弦波信号频谱分析为例分析如下: 1.含有频率f ,2f和3f的正弦波叠加信号,即: 其中,f =500Hz.试采用Matlab仿真软件对该信号进行频谱分析 ...
- Python基础简介
一.目前各种语言的应用:java, 可以把特别小的项目做大,并且开源库比较多,C: 用在最底层,例如编写操作系统,运行速率快,开发效率低,C++:常坐游戏引擎Python:AI(人工智能) 简单.明确 ...
- pandas协助工具
pandas有时候操作很不方便,也有可能是我不熟练吧,反正就是各种别扭.下面是我写的一个简单的json数据操作工具,能够完成简单的数据分析工作,后续会不断完善的 # coding=utf-8 impo ...
- Advanced Fruits (最大公共子序列的路径打印)
The company "21st Century Fruits" has specialized in creating new sorts of fruits by trans ...
- 20162328蔡文琛week01
学号20162328 <程序设计与数据结构>第1周学习总结 教材学习内容总结 通过练习课本上给出的代码并结合老师所提供教程,熟悉并初步了解Java的基本编辑 教材学习中的问题和解决过程 无 ...
- android BadgeView的使用(图片上的文字提醒)
BadgeView主要是继承了TextView,所以实际上就是一个TextView,底层放了一个label,可以自定义背景图,自定义背景颜色,是否显示,显示进入的动画效果以及显示的位置等等: 这是Gi ...