【树哈希】CF1182D Complete Mirror

news2024/11/20 14:29:34

CF1182D - Complete Mirror

Description

给定一个 n n n 个点的无根树,求一个树根 r o o t root root,使得对于任意两个节点 v 1 , v 2 v_1,v_2 v1,v2,若满足 d i s t ( v 1 , r o o t ) = d i s t ( v 2 , r o o t ) dist(v_1,root)=dist(v_2,root) dist(v1,root)=dist(v2,root),则必有 d g r ( v 1 ) = d g r ( v 2 ) dgr(v_1)=dgr(v_2) dgr(v1)=dgr(v2),无解输出 − 1 -1 1

d i s t ( u , v ) dist(u,v) dist(u,v)定义为 u , v u,v u,v 之间的边数, d g r ( v ) dgr(v) dgr(v) 定义为与 v v v 点直接相连的点的个数。


Solution

如果以某一个点为根时,树满足如上条件的充分必要条件为在第一个分叉点的所有儿子所构成的子树均为同构的。

例:

如图,第一个分叉点为 3 3 3 号点,所有儿子为 4 , 5 4,5 4,5 号点,显然他们所构成的子树是同构的。

那么,问题变成了如何找出第一个分叉点以及判断子树均同构

子树均同构

树哈希是解决这一类问题最有效的办法,当然树哈希也有好几种,这里小编采取 这一种。

不过,由于该题有换根操作,所以需要考虑如何换根:

d p ( u ) dp(u) dp(u) 表示以 u u u 为根的子树的哈希值,那么 d p ( u ) = ∑ v ∈ s o n ( u ) ( 1 + f ( d p ( v ) ) ) dp(u)=\sum_{v\in son(u)}(1+f(dp(v))) dp(u)=vson(u)(1+f(dp(v)))

对于一棵树:

如果从以 1 1 1 为根换到以 2 2 2 为根,那么哪些子树的哈希值会发生变化呢? 1 1 1 号和 2 2 2 号节点的子树的哈希值会发生变化,其余均不发生任何变化。

考虑 1 1 1 号节点子树哈希值:

  • 原来: d p ( 1 ) = 1 + f ( d p ( 2 ) ) + 1 + f ( d p ( 5 ) ) dp(1)=1+f(dp(2))+1+f(dp(5)) dp(1)=1+f(dp(2))+1+f(dp(5))
  • 现在: d p ( 1 ) = 1 + f ( d p ( 5 ) ) dp(1)=1+f(dp(5)) dp(1)=1+f(dp(5))

故,当 u u u 换根到 v v v 时, d p ( u ) = d p ( u ) − 1 − f ( d p ( v ) ) dp(u)=dp(u)-1-f(dp(v)) dp(u)=dp(u)1f(dp(v))

考虑 2 2 2 号节点子树哈希值:

  • 原来: d p ( 2 ) = 1 + f ( d p ( 3 ) ) + 1 + f ( d p ( 4 ) ) dp(2)=1+f(dp(3))+1+f(dp(4)) dp(2)=1+f(dp(3))+1+f(dp(4))
  • 现在: d p ( 2 ) = 1 + f ( d p ( 3 ) ) + 1 + f ( d p ( 4 ) ) + 1 + f ( d p ( 1 ) ) dp(2)=1+f(dp(3))+1+f(dp(4))+1+f(dp(1)) dp(2)=1+f(dp(3))+1+f(dp(4))+1+f(dp(1)),注意这里的 d p ( 1 ) dp(1) dp(1) 为更改后的 d p dp dp 值。

故,当 u u u 换根到 v v v 时, d p ( v ) = d p ( v ) + 1 + f ( d p ( v ) ) dp(v)=dp(v)+1+f(dp(v)) dp(v)=dp(v)+1+f(dp(v)),注意这里的 d p ( v ) dp(v) dp(v) 为更改后的 d p dp dp 值。

这样,就可以快速判断子树同构了!


第一个分叉点

这个确实不是很好直接干,直接干容易超时,不过转化一下:当以该分叉点为根时会发生什么?

若树为如下所示:

1 1 1 个分叉点为 3 3 3,将 3 3 3 为根时:

可以发现如果以分界点为根时,有 1 1 1 条链以及其余子树均同构,那么把这条链的端点移为根时,那么就是一颗满足条件的树,故这时候输出那条链的端点即可。

其余情况就判断所有儿子的子树是否均同构即可。更多小细节留给大家思考,这里不再赘述。


Code

其中代码前半段为取模板子,删掉后大概 112 112 112 行。

#include <bits/stdc++.h>
#define fi first
#define se second
#define int long long

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

const int MOD = 1e9 + 7;
int ksm(int a, int b) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % MOD;
		a = a * a % MOD;
		b >>= 1;
	}
	return res;
}
void exgcd(int a, int b, int &x, int &y) {
	if (!b) {
		x = 1, y = 0;
		return;
	}
	exgcd(b, a % b, y, x);
	y -= a / b * x;
}
struct Mint {
	int v;
	void assign(int x) {
		v = x;
	}
	Mint operator+ (const Mint tmp)const {
		Mint res;
		res.v = (v + tmp.v) % MOD;
		return res;
	}
	Mint operator+ (const int tmp)const {
		Mint res;
		res.v = (v + tmp) % MOD;
		return res;
	}
	Mint operator- (const Mint tmp)const {
		Mint res;
		res.v = (v - tmp.v + MOD) % MOD;
		return res;
	}
	Mint operator- (const int tmp)const {
		Mint res;
		res.v = (v - tmp + MOD) % MOD;
		return res;
	}
	Mint operator* (const Mint tmp)const {
		Mint res;
		res.v = v * tmp.v % MOD;
		return res;
	}
	Mint operator* (const int tmp)const {
		Mint res;
		res.v = v * tmp % MOD;
		return res;
	}
	Mint operator/ (const Mint tmp)const {
		int x, y;
		exgcd(tmp.v, MOD, x, y), x = (x % MOD + MOD) % MOD;
		Mint res;
		res.v = v * x % MOD;
		return res;
	}
	Mint operator/ (const int tmp)const {
		int x, y;
		exgcd(tmp, MOD, x, y), x = (x % MOD + MOD) % MOD;
		Mint res;
		res.v = v * x % MOD;
		return res;
	}
	Mint operator^ (Mint b)const {
		Mint ans;
		ans.v = ksm(v, b.v);
		return ans;
	}
	Mint operator^ (int b)const {
		Mint ans;
		ans.v = ksm(v, b);
		return ans;
	}
	void read() {
		string s;
		cin >> s;
		for (auto i : s)
			v = (v * 10 + i - '0') % MOD;
	}
};

const int N = 1e5 + 10;

int n;
std::vector<int> G[N];
Mint dp[N];
int far[N];

Mint h(Mint x) {
	return x * x * x * 1237123 + 1145141;
}
Mint f(Mint x) {
	Mint ok, res;
	res.v = 0;
	ok.v = (x.v & ((1ll << 31) - 1)), res = res + h(ok);
	ok.v = (x.v >> 31), res = res + h(ok);
	return res;
}
Mint dfs1(int u, int fa) {
	for (auto v : G[u]) {
		if (v == fa) continue;
		dp[u] = dp[u] + 1 + f(dfs1(v, u));
	}
	return dp[u];
}
void dfs2(int u, int fa) {
	unordered_map<int, int> cnt;
	int tot = 0;
	for (auto v : G[u]) {
		cnt[dp[v].v] ++, tot ++;
	}
	if (tot >= 3) {
		if (cnt.size() == 2) {
			for (auto v : G[u])
				if (cnt[dp[v].v] == 1 && far[v]) {
					cout << far[v] << endl;
					exit(0);
				}
		}
		if (cnt.size() == 1) {
			cout << u << endl;
			exit(0);
		}
	} else if (tot == 2) {
		if (cnt.size() == 1) {
			cout << u << endl;
			exit(0);
		}
	}

	for (auto v : G[u]) {
		if (v == fa) continue;
		Mint tmp1 = dp[u], tmp2 = dp[v];
		int tf1 = far[v], tf2 = far[u];
		dp[u] = dp[u] - 1 - f(dp[v]), dp[v] = dp[v] + 1 + f(dp[u]);
		if (G[u].size() == 2) {
			if (v == G[u][0] && far[G[u][1]]) far[u] = far[G[u][1]];
			if (v == G[u][1] && far[G[u][0]]) far[u] = far[G[u][0]];
		} else if (G[u].size() == 1) {
			far[u] = u;
		}
		far[v] = 0;
		dfs2(v, u);
		dp[u] = tmp1, dp[v] = tmp2, far[v] = tf1, far[u] = tf2;
	}
}
void dfs3(int u, int fa) {
	int tot = 0, p;
	for (auto v : G[u]) {
		if (v == fa) continue;
		tot ++, p = v;
		dfs3(v, u);
	}
	if (tot == 1) far[u] = far[p];
	if (tot == 0) far[u] = u;
}

signed main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);

	cin >> n;

	int u, v, fir = 0;
	for (int i = 1; i < n; i ++) {
		cin >> u >> v, G[u].emplace_back(v), G[v].emplace_back(u);
		if (!fir) fir = u;
	}

	dfs1(1, -1);
	dfs3(1, -1);
	if (far[1] || (G[1].size() == 2 && far[G[1][0]] && far[G[1][1]])) {
		if (far[1]) cout << 1 << endl;
		else cout << far[G[1][0]] << endl;
		return 0;
	}
	dfs2(1, -1);

	cout << -1 << endl;

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1593838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CSS】SVG图片属性及修改颜色

最近的开发中遇到了SVG不能修改颜色的问题&#xff0c;以前是直接用&#xff0c;没有研究过&#xff0c;现在搞个笔记记录下 SVG的属性&#xff1a; width:设置最终SVG图片的宽度height:设置最终SVG图片的高度viewbox&#xff1a;视区&#xff0c;在svg上截取一块&#xff0c…

C++--用list容器处理约瑟夫环问题

约瑟夫环 约瑟夫环问题是一个经典的数学问题&#xff0c;描述如下&#xff1a; 假设有 n 个人站成一圈&#xff0c;编号从 1 到 n。从第一个人开始报数&#xff0c;报到 m 的人出列&#xff0c;然后下一个人继续从 1 开始报数&#xff0c;直到所有人都出列为止。问最后留下的…

013:vue3 Pinia详解使用详解

文章目录 1. Pinia 是什么2. Pinia 功能作用3. 手动添加Pinia到Vue项目4. Pinia基础使用5. getters实现6. action异步实现7. storeToRefs工具函数8. Pinia的调试9. 总结 1. Pinia 是什么 Pinia 是 Vue 的专属的 最新状态管理库是 Vuex 状态管理工具的替代品和 Vuex 一样为 Vue…

ESP-IDF移植lvgl 驱动 ST7789

文章目录 1 前言2 准备3 移植LVGL3.1 工程准备3.2 修改 CMakeLists.txt文件编译 LVGL3.3 编译LVGL 4 编译 ST7789 LCD驱动5 发现问题 1 前言 本教程开始学习 LVGL的&#xff0c;开始之前要把环境配置好&#xff0c;首先就需要移植 lvgl&#xff0c;使用的是 esp32 环境&#xf…

计算机网络——ARP协议

前言 本博客是博主用于复习计算机网络的博客&#xff0c;如果疏忽出现错误&#xff0c;还望各位指正。 这篇博客是在B站掌芝士zzs这个UP主的视频的总结&#xff0c;讲的非常好。 可以先去看一篇视频&#xff0c;再来参考这篇笔记&#xff08;或者说直接偷走&#xff09;。 …

Javaweb监听器(Listener)

一、概念 1.Listener表示监听器。是Javaweb三大组件&#xff08;Servlet、Filter、Listener&#xff09;之一 2.优先级为监听器>过滤器>servlet 3.监听器可以监听就是在application&#xff0c;session&#xff0c;request三个对象创建、销毁或者往其中添加修改删除属性…

MySQ数据库: MySQL数据库的安装配置 ,图文步骤详细,一篇即可完成安装完成! MySQL数据库如何与客户端连接

LiuJinTao&#xff1a; 2024年4月14日 文章目录 MySQL的安装配置1. 下载2. 安装 三、 MySQL 启动与停止1. 第一种 方式&#xff1a;2. 第二种方式&#xff1a; 四、MySQL 客户端连接2. 方式二&#xff1a; MySQL的安装配置 1. 下载 官方下载网址&#xff1a;https://www.mysq…

2024蓝桥杯省赛C++软件算法研究生组题解+游记

A题 给你一个音游的游戏记录log.txt&#xff0c;判断玩家的最高连击数 题解 水题&#xff0c;但是要小心&#xff0c;miss的键需要重置k0&#xff0c;超时但正确的键重置k1 个人答案是9 B题 计算1~2024041331404202中有多少个数x满足x! - x*(x1)/2能被100整除 题解 首先…

数字乡村创新实践探索农业现代化与乡村振兴新路径:科技赋能农村全面振兴与农民幸福新篇章

随着信息技术的飞速发展&#xff0c;数字乡村成为推动农业现代化与乡村振兴的重要战略举措。科技赋能下的数字乡村创新实践&#xff0c;不仅提升了农业生产的智能化水平&#xff0c;也为乡村治理和农民生活带来了翻天覆地的变化。本文旨在探讨数字乡村创新实践在农业现代化与乡…

【vue】Vue3开发中常用的VSCode插件

Vue - Official&#xff1a;vue的语法特性&#xff0c;如代码高亮&#xff0c;自动补全等 Vue VSCode Snippets&#xff1a;自定义一些代码片段 v3单文件组件vdata数据vmethod方法 别名路径跳转 参考 https://www.bilibili.com/video/BV1nV411Q7RX

Java+vue2+springboot智慧班牌系统源码,支持PC端、移动客户端、电子班牌端,SaaS模式部署

智慧班牌作为一个班级的标识&#xff0c;也是班级空间日常管理的载体&#xff0c;作为班级文化展示交流窗口与学科教学、德育管理&#xff0c;以及学校信息収布等有机结合起来&#xff0c;作为学生展示的平台&#xff0c;又可应用于普及教育安全知识和科学文化&#xff0c;拓展…

JVM复习

冯诺依曼模型与计算机处理数据过程相关联&#xff1a; 冯诺依曼模型&#xff1a; 输入/输出设备存储器输出设备运算器控制器处理过程&#xff1a; 提取阶段&#xff1a;输入设备传入原始数据&#xff0c;存储到存储器解码阶段&#xff1a;由CPU的指令集架构ISA将数值解…

斯坦福DeepMindGoogle提出SAFE:大模型长篇事实检验新标杆

关注公众号【AI论文解读】回复或者发送&#xff1a;论文解读 获取本文论文PDF 引言&#xff1a;大型语言模型的长篇事实性挑战 在当今信息爆炸的时代&#xff0c;大型语言模型&#xff08;LLMs&#xff09;在处理开放式话题的事实性问题时&#xff0c;常常会产生包含事实错…

【进阶六】Python实现SDVRPTW常见求解算法——自适应大邻域算法(ALNS)

基于python语言&#xff0c;采用经典自适应大邻域算法&#xff08;ALNS&#xff09;对 带硬时间窗的需求拆分车辆路径规划问题&#xff08;SDVRPTW&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整2.1 需求拆分2.2 需求拆分后的服务时长取值问题 3. 求解结果4…

基本的数据类型在16位、32位和64位机上所占的字节大小

1、目前常用的机器都是32位和64位的&#xff0c;但是有时候会考虑16位机。总结一下在三种位数下常用的数据类型所占的字节大小。 数据类型16位(byte)32位(byte)64位(byte)取值范围char111-128 ~ 127unsigned char1110 ~ 255short int / short222-32768~32767unsigned short222…

gitlab:Could not resolve host

fatal: unable to access http://xxx.git/: Could not resolve host: yyy Git-fatal: unable to access ‘https://gitlab.XX.git/‘: Could not resolve host: gitlab.XX.com.cn_drone unable to access .git/: could-CSDN博客 原因&#xff1a; 克隆的时候使用的是这里的HTT…

mysql题目5

tj11&#xff1a; select max(c.teacher_age) 最大的年龄 from tb_teacher c tj12: select a.class_name 班级名称,b.student_name 学生姓名,b.gender 学生性别 from tb_class a join tb_student b on a.class_idb.class_id join tb_teacher c on a.teacher_idc.teacher_id w…

复旦新出!大规模语言模型:从理论到实践,书籍PDF分享

自2018年以来&#xff0c;包含Google、OpenAI、Meta、百度、华为等公司和研究机构都纷纷发布了包括BERT&#xff0c; GPT等在内多种模型&#xff0c;并在几乎所有自然语言处理任务中都表现出色。 今天给大家推荐一本大模型方面的书籍<大规模语言模型&#xff1a;从理论到实…

Python学习笔记20 - 模块

什么叫模块 自定义模块 Python中的包 Python中常用的内置模块 第三方模块的安装与使用

虚拟机安装及拉取阿里云镜像

虚拟机安装及拉取阿里云镜像 1: 2: 3: 4: 5: 6: 7:这里设置为处理器核数的一半 8: 9: 10: 11: 12: 13: 14: 15: 16: 选好 光盘镜像文件后;点击关闭 按钮;然后选择完成 17: 18: 19: 20: 开始漫长的等待… 21: 点击完成配置,然后开始等待 22: 23: 24: 然后点击右下角的 完成配…