牛客算法周周练1 C. Borrow Classroom(二分/LCA)

题目链接:https://ac.nowcoder.com/acm/contest/5086/C

题意

一棵树上一个人要从结点 $B$ 移动到结点 $C$ 再移动到根节点 $1$,问另一个人能否从结点 $A$ 出发在根节点前拦截到第一个人。

题解

拦截成功的情况分为三种:

  • $dis_{AC} ≤ dis_{BC}$
  • $dis_{A1} < dis_{BC} + dis_{C1}$
  • $dis_{A1} = dis_{BC} + dis_{C1},LCA_{AC}\ != 1$

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
 
vector<int> e[N];
int parent[30][N];
int depth[N];
 
void dfs(int v, int u, int dep) {
    parent[0][v] = u;
    depth[v] = dep;
    for (auto w : e[v])
        if (w != u)
            dfs(w, v, dep + 1);
}
 
int LCA(int u, int v) {
    if (depth[u] > depth[v]) swap(u, v);
    for (int k = 0; k < 30; k++) {
        if ((depth[v] - depth[u]) >> k & 1) {
            v = parent[k][v];
        }
    }
    if (u == v) return u;
    for (int k = 30 - 1; k >= 0; k--) {
        if (parent[k][u] != parent[k][v]) {
            u = parent[k][u];
            v = parent[k][v];
        }
    }
    return parent[0][u];
}
 
int dis(int u, int v) {
    int t = LCA(u, v);
    return depth[u] - depth[t] + depth[v] - depth[t];
}
 
void solve() {
    for (auto &vec : e) vec.clear();
    int n, q; cin >> n >> q;
    for (int i = 0; i < n - 1; i++) {
        int u, v; cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1, 0, 0);
    for (int k = 0; k + 1 < 30; k++) {
        for (int v = 1; v <= n; v++) {
            if (parent[k][v] == 0) parent[k + 1][v] = 0;
            else parent[k + 1][v] = parent[k][parent[k][v]];
        }
    }
    for (int i = 0; i < q; i++) {
        int A, B, C; cin >> A >> B >> C;
        bool ok = false;
        int disAC = dis(A, C);
        int disBC = dis(B, C);
        int disA1 = depth[A] - depth[1];
        int disC1 = depth[C] - depth[1];
        if ((disAC <= disBC) or (disA1 < disBC + disC1) or (disA1 == disBC + disC1 and LCA(A, C) != 1))
            ok = true;
        cout << (ok ? "YES" : "NO") << "\n";
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    int t; cin >> t;
    while (t--) solve();
}

参考博客:https://www.cnblogs.com/zufezzt/p/6804426.html

posted @ 2020-05-30 21:15  Kanoon  阅读(171)  评论(0)    收藏  举报