「LCA」仓鼠找sugar

时间:2019-09-06
本文章向大家介绍「LCA」仓鼠找sugar,主要包括「LCA」仓鼠找sugar使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

仓鼠找sugar

原题链接 仓鼠找sugar

题目大意

给你 \(n\) 个点, \(q\) 次询问,\(n - 1\) 条边,每条边给出 \(u, v\) 两个点,代表 \(u, v\) 被一条边连接,接下来是\(q\)次询问,每次询问给你 \(x_1,y_1,x_2,y_2\) 让你判断 \(x_1\)\(y_1\)\(x_2\)\(y_2\) 是否会经过相同的点

题目题解

跑LCA,然后判断

dist<x1, y1> + dist<x2, y2> >= dist<x1, x2> + dist<y1, y2>

dist<x, y> = depth[x] + depth[y] - 2 × depth[lca(x, y)]

第二个就是一个计算两点深度的,不多做解释,重点关注第一个不等式,以下证明正确性

分类证明:

  • 对于一棵树而言 \(x_1,y_1\) 在根节点的左树里面, \(x_2, y_2\) 在根节点的右树里面 这样一定满足不等式
  • 对于一棵树而言 \(x_1.y_1,x_2,y_2\) 同时在根节点的左树(右树)里,那么此时又分情况
    • 将其左树(右树)看成一棵以原根节点的下一个节点为根节点的树,此时分三种情况
    • \(x_1,y_1\)\(x_2, y_2\) 在不同边,此时满足我们第一点所说
    • \(x_1\) 或某一个点在左树,其他点在右树,将左侧的\(x_1\)或其他点与右树应该加的点进行加法,然后再将右树的点用第一点所说处理即可,最终可以发现是满足我们的不等式
    • \(x_1, y_2\) 同树,\(x_2,y_1\) 同树 参考第一点进行处理
    • 还有一种没有意义的情况就是再出现同在左树右树的情况 再以原树的根节点的下一点为根进行处理即可
  • 若就在原树中发生上述情况,也可按上述情况来进行处理,任何形态都是一样的

详细看代码

//#define fre yes

#include <cstdio>
#include <cstring>
#include <iostream>

const int N = 100005;
int head[N << 1], to[N << 1], ver[N << 1];
int depth[N], f[N][22], lg[N];
bool Vis[N];

int tot;
void addedge(int x, int y) {
    ver[tot] = y;
    to[tot] = head[x];
    head[x] = tot++;
}

void dfs(int x, int fa) {
    depth[x] = depth[fa] + 1;
    f[x][0] = fa;
    for (int i = 1; (1 << i) <= depth[x]; i++) {
        f[x][i] = f[f[x][i - 1]][i - 1];
    }

    for (int i = head[x]; ~i; i = to[i]) {
        int v = ver[i];
        if(v != fa) {
            Vis[v] = 1;
            dfs(v, x);
        }
    }
}

int lca(int a, int b) {
    if(depth[a] < depth[b]) {
        std::swap(a, b);
    }

    while(depth[a] > depth[b]) {
        a = f[a][lg[depth[a] - depth[b]] - 1];
    }

    if(a == b) return a;

    for (int i = lg[depth[a]] - 1; i >= 0; i--) {
        if(f[a][i] != f[b][i]) {
            a = f[a][i];
            b = f[b][i];
        }
    } return f[a][0];
}

int dist(int a, int b) {
    return depth[a] + depth[b] - 2 * depth[lca(a, b)];
}

int main() {
    memset(head, -1, sizeof(head));
    static int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }

    for (int i = 1; i <= n; i++) {
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
    }

    for (int i = 1; i <= n; i++) {
        if(!Vis[i]) {
            Vis[i] = 1;
            dfs(i, -1);
        }
    }

    for (int i = 1; i <= m; i++) {
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        if(dist(x1, y1) + dist(x2, y2) >= dist(x1, x2) + dist(y1, y2)) puts("Y");
        else puts("N");
    } return 0;
}

原文地址:https://www.cnblogs.com/Nicoppa/p/11477981.html