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. Linux命令应用大词典-第30章 审计系统

    30.1 auditctl:控制内核的审计系统 30.2 aureport:生成审计信息报表 30.3 ausearch:搜索审计记录 30.4 autrace:跟踪指定进程 30.5 audit-v ...

  2. <cctype>

    头文件名称:  <cctype> (ctype.h) 头文件描述: 这是一个拥有许多字符串处理函数声明的头文件,这些函数可以用来对单独字符串进行分类和转换: 其中的函数描述: 这些函数传入 ...

  3. 创建一个socket服务实时统计在线人数

    主要是两个文件,一个是后端文件,一个是前端文件: 后端文件:有人登录了,就通知所有的正在访问的页面,把总人数+1:反之-1: 前端文件:有人登录了,通知后端,页面关闭了,通知后端,同时接收后端派发来的 ...

  4. JavaScript 之 对象/JSON/数组

    对象 简单说,所谓对象,就是一种无序的数据集合,由若干个“键值对”(key-value)构成. var obj = { p: 'Hello World' }; 上面代码中,大括号就定义了一个对象,它被 ...

  5. Java VisualVM使用

    Java VisualVM Java VisualVM官网 Java VisualVM介绍 Java VisualVM is a tool that provides a visual interfa ...

  6. 【C#】arcface人脸识别使用问题分析

    arcface上线了新版 正好有空 赶紧下载体验了一番 凡是过程中也遇到一些问题 1.初始化 [DllImport("libarcsoft_face_engine.dll", En ...

  7. 机器学习实战笔记一:K-近邻算法在约会网站上的应用

    K-近邻算法概述 简单的说,K-近邻算法采用不同特征值之间的距离方法进行分类 K-近邻算法 优点:精度高.对异常值不敏感.无数据输入假定. 缺点:计算复杂度高.空间复杂度高. 适用范围:数值型和标称型 ...

  8. 家用甲醛pm2.5温湿度传感器实验

    最近在装修房子,刷完墙漆铺完了木地板以后,屋里边有很大的味,所以就买了 攀藤科技的PMS5003ST G5ST PM2.5激光粉尘甲醛温湿度三合一传感器,打算自己测一下甲醛浓度,看看什么时候能够入住. ...

  9. Alpha发布文案加美工展示

    目录 团队简介 项目进展 组内分工 队员总结 后期计划 一.团队简介 二.项目进展 从选题发布到今天的Alpha发布,我们团队经历了许许多多的磨难.我们最终设计了如下的功能:首页.班级.个人.更多.打 ...

  10. Calculation PartⅡ

    GitHub/object-oriented 误删内容--周末修复