P4281 [AHOI2008]紧急集合 / 聚会

此题来到LCA较高等级运用。

这道题需要自己花一些树玩玩。

找到一些性质:

  1. 三个点的lca一定至少有两个是一样的;更多证明
  2. 集合点就是不相同的点;

同时还要会求树上距离

image

这里 x,y,z 是三个人,l 是重复lca,p 就是集合点。那么距离就是 dep(y)dep(p)+dep(z)dep(p)+dep(x)dep(l)+dep(p)dep(l) 简化一下就是 dep(x)+dep(y)+dep(z)dep(l)2+dep(p)

一般地就是 dep(x)+dep(y)+dep(z)dep(lca1)dep(lca2)dep(lca3)

因为重复项乘2 也就是两个相加罢了。

#include <bits/stdc++.h>
#define ll long long
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
using namespace std;
const int maxn = 5 * 100002;
int n, m;
int f[maxn][20];
int dep[maxn];
vector<int>e[maxn];
void dfs(int u, int fa)
{
	f[u][0] = fa;
	dep[u] = dep[fa] + 1;
	for (int i = 1; i <= 19; i++) {
		f[u][i] = f[f[u][i - 1]][i - 1];
	}
	for (int i : e[u]) {
		if (i != fa) {
			dfs(i, u);
		}
	}
}
int lca(int u, int v)
{
	if (dep[u] <dep[v]) swap(u,v);
	for (int i = 19; i >= 0; i--) {
		if (dep[f[u][i]] >= dep[v]) {
			u = f[u][i];
		}
	}
	if (u == v) {
		return v;
	}
	for (int i = 19; i >= 0; i--) {
		if (f[u][i] != f[v][i]) {
			u = f[u][i];
			v = f[v][i];
		}
	}
	return f[u][0];
}
int main()
{
	n = read(), m =read();
	for (int i = 1, a, b; i < n; i++) {
		a = read(), b = read();
		e[a].push_back(b);
		e[b].push_back(a);
	}
	dfs(1, 0); // root?
	int a, b, c;
	for (int kase = 1; kase <= m; kase ++) {
		a = read(); b = read(); c = read();
		int l1 = lca(a, b);
		int l2 = lca(a, c);
		int l3 = lca(b, c);
		int ansl;
		if (l1 == l2) {
			ansl = l3;
		} else if (l2 == l3) {
			ansl = l1;
		} else {
			ansl = l2;
		}
		printf("%d %d\n", ansl, dep[a] + dep[b] + dep[c] - dep[l1] - dep[l2] - dep[l3]);
	}
    return 0;
}
posted @   Vegdie  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示