树上二分(树的重心)

题目来源

Problem - G - Codeforces

题目介绍

给定log2n次机会,去猜出树上的一个特殊的点。

解题思路

由给定的机会,很容易看出这是一个在树上二分题目,所以我们可以利用树的重心来保证每次可以去除树上一半的点,最后即可求出答案。

解题代码

cpp 复制代码
void dfs(ll u, ll v) {
	siz[u] = 1;
	maxtree[u] = 0;
	for (auto it : edge[u]) {
		if (it == v || flag[it]) continue;
		dfs(it, u);
		siz[u] += siz[it];
		maxtree[u] = max(siz[it], maxtree[u]);
	}
	maxtree[u] = max(maxtree[u], S - siz[u]);
	if (maxtree[u] < maxtree[root]) root = u;
}

这段代码通过dfs求出siz数组和maxtree数组,siz数组是树上点的子树大小,maxtree数组是去除该点的后剩余子树之中节点个数最多的数量

cpp 复制代码
ll check(ll x, ll y) {
	cout << "? " << x << " " << y << "\n";
	ll pp; cin >> pp;
	return pp;
}

通过交互来获取下一步怎么做

cpp 复制代码
ll dfs1(ll x) {
	dfs(x, 0);
	vector<ll> son;
	for (auto it : edge[x]) {
		if (!flag[it]) son.push_back(it);
	}
	sort(son.begin(), son.end(), [&](auto x, auto y) {return siz[x] > siz[y]; });
	if (son.size() == 0) return x;
	else if (son.size() == 1) {
		ll pp = check(x, son[0]);
		if (pp == 0) return x;
		else return son[0];
	}
	else if (son.size() == 2) {
		ll pp = check(son[0], son[1]);
		if (pp == 1) return x;
		if (pp == 0) {
			S = siz[son[0]];
			root = 0;
			flag[x] = 1;
			dfs(son[0], 0);
			return dfs1(root);
		}
		else {
			S = siz[son[1]];
			root = 0;
			flag[x] = 1;
			dfs(son[1], 0);
			return dfs1(root);
		}
	}
	else {
		ll pp = check(son[0], son[1]);
		if (pp == 1) {
			S = siz[son[2]] + 1;
			root = 0;
			flag[son[0]] = 1;
			flag[son[1]] = 1;
			dfs(x, 0);
			return dfs1(root);
		}
		else if (pp == 0) {
			S = siz[son[0]];
			root = 0;
			flag[x] = 1;
			dfs(son[0], 0);
			return dfs1(root);
		}
		else {
			S = siz[son[1]];
			root = 0;
			flag[x] = 1;
			dfs(son[1], 0);
			return dfs1(root);
		}
	}
}

我们可以对重心x这个点进行下面四个处理

1:x度数为0:直接返回答案x。

2:x度数为1:使用check()询问x和该点即可知道答案,然后返回该值就行。

二分3:x度数为2:使用check()询问x的两个相邻的点,求出之后的重心,再进行dfs1()。

4:x度数为3:使用check()询问x的三个相邻的点中较大的两个。最小的那个连 通块加一,因为要算上x本身,最后根据check()返回值求出之后的重心,再进行dfs1()。

最后求出该题的答案

总结

该题主要利用二分的思想和树的重心去解决这道题目,总体不难,但是其中分类去跑下一次dfs1()的细节比较多。

相关推荐
liulilittle1 分钟前
Linux 下 select 测试函数
linux·服务器·网络·数据库·c++·select·c
Logic1019 分钟前
C语言/数据结构欧几里得算法题解:长方形切割最大正方形——贪心划分计数
c语言·数据结构·算法·贪心算法·时间复杂度·空间复杂度·欧几里得算法
yi01125 分钟前
LeetCode 643. 子数组最大平均数 I|从暴力枚举到滑动窗口
人工智能·笔记·python·算法·leetcode·滑动窗口
无忧.芙桃1 小时前
C++语言原理与实践(十二):list类的底层实现
c++·windows·list
沫璃染墨1 小时前
《Linux工程实践篇(二):线程池实战——从线程安全单例到完整源码实现》
linux·开发语言·c++·单例模式·设计模式·系统架构
极光通讯1 小时前
服务器内存来料检验(IQC)实操:批次追溯、外观判定与上机验证
java·服务器·算法
淡海水1 小时前
02-04-原理篇-GC Roots与对象图遍历
算法·unity·c#·图·gc·遍历·roots
ClickHouseDB1 小时前
ClickHouse 大规模 OpenTelemetry 数据接入架构的可靠性演进
算法
有只小白叫岳飒1 小时前
c++智能指针 unique_ptr与函数调用
c++
Shaoshing1 小时前
BHU 润石工作室 251019自建赛题解
算法