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. C++11 type_traits 之is_pointer,is_member_function_pointer源码分析

    源码如下: template<typename> struct __is_pointer_helper : public false_type { }; template<typen ...

  2. chrome编辑器与截图

    在地址栏中输入 data:text/html,<html contenteditable>即可使用编辑功能,打开控制台,ctrl + shift + p 调用命令面板,输入 capture ...

  3. gitolite 丢失管理密钥/访问权限 解决办法

    登录到服务器. 使用完整路径克隆管理员仓库: git clone $HOME/repositories/gitolite-admin.git temp cd gitolite-admin/conf v ...

  4. Wordcount -- MapReduce example -- Mapper

    Mapper maps input key/value pairs into intermediate key/value pairs. E.g. Input: (docID, doc) Output ...

  5. anaconda安装scrapy报错解决办法

    今天在用anaconda安装scrapy的时候遇见个坑,现在将解决办法发出来,供大家参考使用: 问题描述: anaconda安装scrapy,使用 conda install scrapy 命令.安装 ...

  6. php 面试题

    1.通过哪一个函数,可以把错误转换为异常处理? A:set_error_handlerB:error_reportingC:error2exceptionD:catch 正确答案:A 答案分析:set ...

  7. es6从零学习(二):promise

    es6从零学习(二):promise 一:promise的由来 某些情况下,回调嵌套很多时,代码就会非常繁琐,会给我们的编程带来很多的麻烦,这种情况俗称——回调地狱.由此,Promise的概念就由社区 ...

  8. Git 命令详解及常用命令

    Git 命令详解及常用命令 Git作为常用的版本控制工具,多了解一些命令,将能省去很多时间,下面这张图是比较好的一张,贴出了看一下: 关于git,首先需要了解几个名词,如下: 1 2 3 4 Work ...

  9. Thunder团队第三周 - Scrum会议6

    Scrum会议6 小组名称:Thunder 项目名称:i阅app Scrum Master:宋雨 工作照片: 代秋彤照相,所以图片中没有该同学. 参会成员: 王航:http://www.cnblogs ...

  10. alpha-4

    前言 失心疯病源4 团队代码管理github 站立会议 队名:PMS 530雨勤(组长) 今天完成了那些任务 19:00~21:50 利用背景相减法完成背景构建与更新模块,查找关于blob更多的论文资 ...