https://www.lydsy.com/JudgeOnline/problem.php?id=4754

https://www.luogu.org/problemnew/show/P4323

https://loj.ac/problem/2072

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]独特的树叶——题解的更多相关文章

  1. 洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心)

    洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/132 ...

  2. 洛谷P3387 【模板】缩点 题解

    背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...

  3. [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)

    [NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...

  4. [洛谷P1029]最大公约数与最小公倍数问题 题解(辗转相除法求GCD)

    [洛谷P1029]最大公约数与最小公倍数问题 Description 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P, ...

  5. BZOJ5288 & 洛谷4436 & LOJ2508:[HNOI/AHOI2018]游戏——题解

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

  6. BZOJ4943 & 洛谷3823 & UOJ315:[NOI2017]蚯蚓排队——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4943 http://uoj.ac/problem/315 https://www.luogu.or ...

  7. BZOJ1229 & 洛谷2917:[USACO2008 NOV]toy 玩具 & 洛谷4480:[BJWC2018]餐巾计划问题——题解

    标题很长emmm…… [USACO2008 NOV]toy 玩具 https://www.luogu.org/problemnew/show/P2917 https://www.lydsy.com/J ...

  8. BZOJ3675 & 洛谷3648 & UOJ104:[Apio2014]序列分割——题解

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

  9. 洛谷3258:[USACO2012 MAR]Flowerpot 花盆——题解

    https://www.luogu.org/problemnew/show/P2698#sub 老板需要你帮忙浇花.给出N滴水的坐标,y表示水滴的高度,x表示它下落到x轴的位置. 每滴水以每秒1个单位 ...

随机推荐

  1. 【vps搬家】--总结--费元星

    20150310  费元星 稍微玩VPS/服务器比较久的站长手中应该不止一台VPS,我们会有多台机器之间的相互使用.比如可能会遇到的是数据传输,我们传统的做法是先用FTP下载数据A到本地,然后再到本地 ...

  2. PHP MySQL 安全方案

     1 转义与清除转义 // 对 用户提交的数据 ' " \ 进行转义 if ( get_magic_quotes_gpc() ) { function del_magic_quotes($v ...

  3. tomcat部署项目,80端口被占,解决方案

    第一个解决方案: 最大的可能:被System占了. 解决Windows Server 2008 System进程占用80端口 输入netstat -ano 可以看到80端口被PID4占用,于是打开任务 ...

  4. 在Unity中使用LitJson解析json文件

    LitJson 这个库需要找资源,找到LitJson.dll后将它放在Assets文件夹下,在脚本中使用using引入即可 测试代码 json文件: {"Archice":[{&q ...

  5. 互联网行业求职课-教你进入BAT

    互联网行业求职课--教你进入BAT 课时1. 课程内容介绍.导师介绍.服务安排和介绍等 课时2. 互联网行业.职业选择指导 互联网公司选择: 大公司:收获:大平台,系统思维,系统培训,系统性的发展,薪 ...

  6. Vue 兄弟组件通信(不使用Vuex)

    Vue 兄弟组件通信(不使用Vuex) 项目中,我们经常会遇到兄弟组件通信的情况.在大型项目中我们可以通过引入vuex轻松管理各组件之间通信问题,但在一些小型的项目中,我们就没有必要去引入vuex.下 ...

  7. 【MySQL解惑笔记】忘记MySQL数据库密码

    破解MySQL密码 一.MySQL5.7.5之前 只要有系统root密码就可以破解: [root@host- ~]# vim /etc/my.cnf //在配置文件中加入如下内容 [mysqld] s ...

  8. Hadoop,MapReduce操作Mysql

    前以前帖子介绍,怎样读取文本数据源和多个数据源的合并:http://www.cnblogs.com/liqizhou/archive/2012/05/15/2501835.html 这一个博客介绍一下 ...

  9. HADOOP docker(八):hadoop本地库

    前言2. Native Hadoop Library3. 使用本地库4. 本地库组件5. 支持的平台6. 下载7. 编译8. 运行时观察9. 检查本地库10. 如果共享本地库 小伙伴还记得每次启动hd ...

  10. Java学习个人备忘录之面向对象概念

    对象,其实就是该类事物实实在在存在的个体. 类与对象之间的关系?类:一类事物的描述.对象:该类事物的实例.在java中通过new来创建的.举例来说,类就是汽车说明书,类只能在理论上造一辆汽车,并且这个 ...