题解 P2971【[USACO10HOL]Cow Politics G】

似乎是一个很简洁的新做法。

显然 \(k\) 个点集互不干扰,可以分开处理。

对于每个点集,首先取出两个点 \(u,v\) 作为最远的两个点(为表述方便下文称为直径),然后考虑向点集中加入点 \(w\) 的过程。我们计算出 \(d_1=\operatorname{dis}(u,v),d_2=\operatorname{dis}(u,w),d_3=\operatorname{dis}(v,w)\),则点集的直径为 \(\max\{d_1,d_2,d_3\}\)。判断出哪两个点是新的直径,然后在这个新的直径的基础上继续加点即可。

正确性的话,类似于正常的树的直径,到一个点距离最远的点一定是一条直径的端点。若新的点要作为直径端点,只能是到原来直径两端距离有一个比原来直径要长。

时间复杂度 \(\mathcal O(n\log n)\)

// Problem: P2971 [USACO10HOL]Cow Politics G
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2971
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=(y);x<=(z);x++)
#define per(x,y,z) for(int x=(y);x>=(z);x--)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;
const int N = 2e5+5;

int n, k, a[N], fa[N][19], dis[N], rt;
vector<int> d[N], e[N];
template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
void dfs(int u) {
	dis[u] = dis[fa[u][0]] + 1;
	rep(i, 1, 18) fa[u][i] = fa[fa[u][i-1]][i-1];
	for(int v : e[u]) dfs(v);
}
int LCA(int u, int v) {
	if(dis[u] < dis[v]) swap(u, v);
	per(i, 18, 0) if(dis[fa[u][i]] >= dis[v]) u = fa[u][i];
	if(u == v) return u;
	per(i, 18, 0) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
	return fa[u][0];
}
int dist(int u, int v) {
	return dis[u] + dis[v] - 2 * dis[LCA(u, v)];
}

int main() {
	scanf("%d%d", &n, &k);
	rep(i, 1, n) {
		scanf("%d%d", &a[i], &fa[i][0]);
		if(!fa[i][0]) rt = i;
		d[a[i]].push_back(i);
		e[fa[i][0]].push_back(i);
	}
	dfs(rt);
	rep(i, 1, k) {
		int u = d[i][0], v = d[i][1], sz = d[i].size();
		for(int j=2;j<sz;j++) {
			int w = d[i][j];
			int d1 = dist(u, v), d2 = dist(u, w), d3 = dist(v, w);
			int diameter = max(d1, max(d2, d3));
			int U = 0, V = 0;
			if(d1 == diameter) U = u, V = v;
			else if(d2 == diameter) U = u, V = w;
			else U = v, V = w;
			u = U; v = V;
		}
		printf("%d\n", dist(u, v));
	}
	return 0;
}
posted @ 2022-09-11 18:43  rui_er  阅读(42)  评论(0编辑  收藏  举报