CSP-S 2019 树的重心

树的重心

小简单的课后作业是求出S单独删去每条边后,分裂出的两个子树的重心编号和之和
请你帮小简单完成作业

subtask1 期望得分 40pts

O(n)枚举删去哪一条边 然后dfs找儿子 简单粗暴 时间复杂度O(n2)

subtask2 期望得分 55pts

O(n)扫过去 把重心弄出来就行了

std 期望得分 100pts

有一个性质就是重心一定在这个树重链上 而且 每一个点的重儿子只有一个 很容易想到用倍增去写 然后我们可以dfs一遍 边dfs边换根 (sizeson)的变化 时间复杂度O(nlogn)

inline void work (int u) {
	for (int i = 1; i <= 20; i ++ ) f[u][i] = f[f[u][i - 1]][i - 1];
}

inline void dfs (int u, int fa) {
	size[u] = 1; Fa[u] = fa;
	for (int i = head[u]; i; i = edge[i].next) {
		int v = edge[i].to;
		if (v == fa) continue;
		dfs (v, u);
		size[u] += size[v];
		if (size[v] > size[son[u]]) son[u] = v;
	}
	f[u][0] = son[u];
	work (u);
}

inline void solve (int u, int sz) {
	for (int i = 20; i >= 0; i -- ) {
		if (f[u][i] && size[f[u][i]] * 2 >= sz) u = f[u][i];
	}
	ans += u;
	if (size[u] * 2 == sz) ans += Fa[u];
}

inline void dp (int u, int fa) {
	int s1 = 0, s2 = 0;
	for (int i = head[u]; i; i = edge[i].next) {
		int v = edge[i].to;
		if (size[v] > size[s1]) s2 = s1, s1 = v;
		else if (size[v] > size[s2]) s2 = v;
	}
	for (int i = head[u]; i; i = edge[i].next) {
		int v = edge[i].to;
		if (v == fa) continue;
		int x = s1;
		if (v == x) x = s2;
		size[u] -= size[v];
		f[u][0] = x;
		work (u);
		solve (v, size[v]); solve (u, size[u]);
		size[v] += size[u]; Fa[u] = v;
		dp (v, u);
		size[v] -= size[u]; size[u] += size[v];
	}
	f[u][0] = son[u];
	work (u);
	Fa[u] = fa;
}

分析

55 考场暴力标配 难度普及+

100 用倍增不难想主要是分析性质 想到重儿子就ok了 难度提高+

posted @   Hock  阅读(439)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示