姚望舒 发表于 2025-6-8 12:10:04

最近公共祖先模板

最近公共祖先

题目:https://acm.hdu.edu.cn/showproblem.php?pid=2586

#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//
const int N = 50010;
int f, d, dist;
int e, ne, w, h, idx;
int n, m, t;
void add(int a, int b, int c) {
        e = b, w = c, ne = h, h = idx ++;
}
std::queue<int> q;
void bfs() {
        q.push(1); // 加入根节点
        d = 1; // 根节点的层次为1
        while (q.size()) {
                int x = q.front();
                q.pop();
                for (int i = h; i != -1; i = ne) {
                        int y = e;
                        if (d != -1) continue; // 当前y已经遍历到了,并且已经给深度赋值了
                        d = d + 1; // y的层次等于x的层次加一
                        dist = dist + w; // y到根节点的距离为x到根节点的距离加上边(x,y)的大小
                        f = x; // y向上走2的零次方步到达x
                        for (int j = 1; j <= t; j ++) {
                                f = f]; // y向上走2^j步到达的点就是:y向上走2^(j-1)步到达的点,再向上走2^(j-1)步到达的点
                        }
                        q.push(y); // 加入队列
                }
        }
}

int lca(int x, int y) {
        if (d < d) std::swap(x, y); // 使得x的层次大于y的层次
        for (int i = t; i >= 0; i --) {
                if (d] >= d) {
                        // x向上走2^i次方步都还是比y的深度大,那么还得继续走
                        x = f;
                }
        }
        if (x == y) return y; // 走完之后,x与y相等,那么y就是最近公共祖先,因为y的深度比较大,所以y应该是祖先
        // 否则的话,这两个点的深度应该是相等的
        for (int i = t; i >= 0; i --) {
                // 同时往上移动
                if (f != f) {
                        x = f;
                        y = f;
                }
        }
        return f; // 最终这两个点的父节点就是最近公共祖先
}

int main()
{
        int T;
        std::cin >> T;
        while (T --) {
                std::cin >> n >> m;
                t = (int)(log(n) / log(2)) + 1;
                // 清空
                memset(h, -1, sizeof h);
                memset(d, -1, sizeof d);
                idx = 0;
                // 读入一棵树
                for (int i = 1; i < n; i ++) {
                        int x, y, z;
                        std::cin >> x >> y >> z;
                        add(x, y, z);
                        add(y, x, z);
                }
                bfs(); // 预处理信息
                // 回答问题
                for (int i = 1; i <= m; i ++) {
                        int x, y;
                        std::cin >> x >> y;
                        std::cout << dist + dist - 2 * dist << "\n"; // 两个点的距离为两个点到根节点的距离之和减去2倍最近公共祖先到根节点的距离
                }
        }
        return 0;
}此时结束之后,应满足向上2^i次方步他们相等
最后x的父节点f就是答案

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 最近公共祖先模板