最近公共先人模板

打印 上一主题 下一主题

主题 1379|帖子 1379|积分 4137

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
最近公共先人

标题:https://acm.hdu.edu.cn/showproblem.php?pid=2586
  1. #include <bits/stdc++.h>
  2. using u32 = unsigned;
  3. using i64 = long long;
  4. using u64 = unsigned long long;
  5. //
  6. const int N = 50010;
  7. int f[N][20], d[N], dist[N];
  8. int e[2*N], ne[2*N], w[2*N], h[2*N], idx;
  9. int n, m, t;
  10. void add(int a, int b, int c) {
  11.         e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
  12. }
  13. std::queue<int> q;
  14. void bfs() {
  15.         q.push(1); // 加入根节点
  16.         d[1] = 1; // 根节点的层次为1
  17.         while (q.size()) {
  18.                 int x = q.front();
  19.                 q.pop();
  20.                 for (int i = h[x]; i != -1; i = ne[i]) {
  21.                         int y = e[i];
  22.                         if (d[y] != -1) continue; // 当前y已经遍历到了,并且已经给深度赋值了
  23.                         d[y] = d[x] + 1; // y的层次等于x的层次加一
  24.                         dist[y] = dist[x] + w[i]; // y到根节点的距离为x到根节点的距离加上边(x,y)的大小
  25.                         f[y][0] = x; // y向上走2的零次方步到达x
  26.                         for (int j = 1; j <= t; j ++) {
  27.                                 f[y][j] = f[f[y][j-1]][j-1]; // y向上走2^j步到达的点就是:y向上走2^(j-1)步到达的点,再向上走2^(j-1)步到达的点
  28.                         }
  29.                         q.push(y); // 加入队列
  30.                 }
  31.         }
  32. }
  33. int lca(int x, int y) {
  34.         if (d[x] < d[y]) std::swap(x, y); // 使得x的层次大于y的层次
  35.         for (int i = t; i >= 0; i --) {
  36.                 if (d[f[x][i]] >= d[y]) {
  37.                         // x向上走2^i次方步都还是比y的深度大,那么还得继续走
  38.                         x = f[x][i];
  39.                 }
  40.         }
  41.         if (x == y) return y; // 走完之后,x与y相等,那么y就是最近公共祖先,因为y的深度比较大,所以y应该是祖先
  42.         // 否则的话,这两个点的深度应该是相等的
  43.         for (int i = t; i >= 0; i --) {
  44.                 // 同时往上移动
  45.                 if (f[x][i] != f[y][i]) {
  46.                         x = f[x][i];
  47.                         y = f[y][i];
  48.                 }
  49.         }
  50.         return f[x][0]; // 最终这两个点的父节点就是最近公共祖先
  51. }
  52. int main()
  53. {
  54.         int T;
  55.         std::cin >> T;
  56.         while (T --) {
  57.                 std::cin >> n >> m;
  58.                 t = (int)(log(n) / log(2)) + 1;
  59.                 // 清空
  60.                 memset(h, -1, sizeof h);
  61.                 memset(d, -1, sizeof d);
  62.                 idx = 0;
  63.                 // 读入一棵树
  64.                 for (int i = 1; i < n; i ++) {
  65.                         int x, y, z;
  66.                         std::cin >> x >> y >> z;
  67.                         add(x, y, z);
  68.                         add(y, x, z);
  69.                 }
  70.                 bfs(); // 预处理信息
  71.                 // 回答问题
  72.                 for (int i = 1; i <= m; i ++) {
  73.                         int x, y;
  74.                         std::cin >> x >> y;
  75.                         std::cout << dist[x] + dist[y] - 2 * dist[lca(x, y)] << "\n"; // 两个点的距离为两个点到根节点的距离之和减去2倍最近公共祖先到根节点的距离
  76.                 }
  77.         }
  78.         return 0;
  79. }
复制代码
此时结束之后,应满足向上2^i次方步他们相称
末了x的父节点f[x][0]就是答案

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

李优秀

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表