此题来到LCA较高等级运用。
这道题需要自己花一些树玩玩。
找到一些性质:
- 三个点的lca一定至少有两个是一样的;更多证明
- 集合点就是不相同的点;
同时还要会求树上距离
这里 \(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(lca_1)-dep(lca_2)-dep(lca_3)\)
因为重复项乘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;
}
标签:ch,fa,dep,AHOI2008,紧急集合,int,P4281,read,lca
From: https://www.cnblogs.com/CYLSY/p/17067600.html