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. Vue框架核心之数据劫持

    本文来自网易云社区. 前瞻 当前前端界空前繁荣,各种框架横空出世,包括各类mvvm框架横行霸道,比如Angular.Regular.Vue.React等等,它们最大的优点就是可以实现数据绑定,再也不需 ...

  2. 了解和分析iOS Crash

    WeTest 导读 北京时间凌晨一点,苹果一年一度的发布会如期而至.新机型的发布又会让适配相关的同学忙上一阵子啦,并且iOS Crash的问题始终伴随着移动开发者.本文将从三个阶段,由浅入深的介绍如何 ...

  3. jdbc 连接各种数据库

    package com.fh.controller.ruitai.util; import java.sql.Connection; import java.sql.DriverManager; im ...

  4. 02-JVM内存模型:虚拟机栈与本地方法栈

    一.虚拟机栈(VM Stack) 1.1)什么是虚拟机栈 虚拟机栈是用于描述java方法执行的内存模型. 每个java方法在执行时,会创建一个“栈帧(stack frame)”,栈帧的结构分为“局部变 ...

  5. word record 2

    word record 2 scavenger // si ga wen ger a person, animal or insect who takes what others have left ...

  6. 初学Direct X(3)

    初学Direct X(3) 1.获取外设输入--键盘以及鼠标 无论是获取鼠标还是键盘的设备,首先得初始化DirectInput,不过先把必要的环境先配置好: 所要用到的头文件以及库文件是(相比于前两次 ...

  7. Unity 编辑器扩展

    自定义检视面板的使用: 先是定义一个脚本文件,我们来修饰它的检视面板: [HelpURL("http://www.baidu.com")] public class Atr : M ...

  8. leetcode-最大子序和(动态规划讲解)

    最大子序和(动态规划讲解) 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输 ...

  9. spark集群安装部署

    通过Ambari(HDP)或者Cloudera Management (CDH)等集群管理服务安装和部署在此不多介绍,只需要在界面直接操作和配置即可,本文主要通过原生安装,熟悉安装配置流程. 1.选取 ...

  10. ionic 日期插件学习

    <ion-header> <ion-navbar> <ion-title> DateTime </ion-title> </ion-navbar& ...