P4281 [AHOI2008]紧急集合 / 聚会
此题来到LCA较高等级运用。
这道题需要自己花一些树玩玩。
找到一些性质:
- 三个点的lca一定至少有两个是一样的;更多证明
- 集合点就是不相同的点;
同时还要会求树上距离
这里 是三个人, 是重复lca, 就是集合点。那么距离就是 简化一下就是
一般地就是
因为重复项乘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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现