[AHOI2008]紧急集合 / 聚会

本文介绍了一种利用LCA(最近公共祖先)算法解决寻找三个结点到一个结点距离之和最小的问题的方法。通过计算两两结点间的LCA,找出其中两个相同的结点,从而确定第三个结点即为所求。文章提供了详细的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

传送门

题解

求三个结点到一个结点距离之和最小的结点以及距离和

求出两两lca,其中有两个相同,答案则为另一个

code

#include <algorithm>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <iomanip>    
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define ull long long
const int maxn = 5e5 + 7;   

inline int read() {
    int s = 0, w = 1;
    char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
    while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
    return s * w;
}

int T, n, m, num_edge = 0;
struct Edge { int next, to, dis; } edge[maxn << 1];
int head[maxn], fa[maxn][20], depth[maxn], dis[maxn];

inline void add(int from, int to, int dis) {
    edge[++num_edge].to = to;
    edge[num_edge].dis = dis;
    edge[num_edge].next = head[from];
    head[from] = num_edge;
}

void bfs(int rt) {
    queue<int> q;
    while (!q.empty()) q.pop();
    fa[rt][0] = rt; depth[rt] = 0; dis[rt] = 0;
    q.push(rt);
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int i = 1; i < 20; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
        for (int i = head[u]; i; i = edge[i].next) {
            int v = edge[i].to;
            if (v == fa[u][0]) continue;
            depth[v] = depth[u] + 1;
            dis[v] = dis[u] + edge[i].dis;
            fa[v][0] = u;
            q.push(v);
        }
    }
}

int lca(int x, int y) {
    if (depth[x] < depth[y]) swap(x, y);
    for (int i = 0; i < 20; ++i) {
        if ((depth[x] - depth[y]) & (1 << i)) x = fa[x][i];
    }
    if (x == y) return x; 
    for (int i = 19; i >= 0; i--) {
        if (fa[x][i] != fa[y][i]) {
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    return fa[x][0];
}

inline int dist (int x, int y) { return dis[x] + dis[y] - 2 * dis[lca(x, y)]; } 

int main() {
    int n, m;
    n = read(), m = read();
    for (int i = 1; i < n; ++i) {
        int a, b;
        a = read(); b = read();
        add(a, b, 1);
        add(b, a, 1);
    }
    bfs(1);
    for (int i = 1; i <= m; ++i) {
        int a, b, c, point;
        a = read(), b = read(), c = read();
        int x = lca(a, b);
        int y = lca(b, c);
        int z = lca(a, c);
        if (x == y) point = z;
        else if (x == z) point = y;
        else point = x;
        printf("%d %d\n", point, dist(a, point) + dist(b, point) + dist(c, point));
    }
    // system("PAUSE");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值