思维训练——CF1304E 1-Trees and Queries

题目链接:https://www.luogu.com.cn/problem/CF1304E

 这道题稍微想了一下就有思路了。

让我们先来简化一下问题,如果没有加边,仅仅是询问的话,那么该怎么做呢。

很明显在两点树上的路径只有一条,那么我们很容易求出u和v的距离dis(u, v)又因为可以来回走,所以就是问dis(u, v) + 2x 是否能 == k

那么这个问题其实就是问dis(u, v) - k 能否被2整除

现在我们考虑加边的情况。加上了一条边其实有三种情况(我想的不是很周到漏掉了第三种

1. 不通过加边 求dis(u, v) + 2x 是否能 == k

2. 通过加边 求dis(u, x) + dis(y, v) + 2x 是否能 == k

3. 通过加边 求dis(u, y) + dis(x, v) + 2x 是否能 == k

同时注意不要大于k就行

需要会LCA基础知识(这里用得是倍增LCA

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 10;

int n, m;
vector<int> G[maxn];
int dep[maxn], lg[maxn];
int f[maxn][32];

void BFS(int x) {
    queue<int> q; q.push(x);
    dep[x] = 1;
    while (q.size()) {
        int u = q.front(); q.pop();
        for (auto v : G[u]) {
            if (dep[v]) continue;
            dep[v] = dep[u] + 1; f[v][0] = u;
            q.push(v);
            for (int j = 1; j <= lg[dep[v]]; ++ j) {
                f[v][j] = f[f[v][j-1]][j-1];
            }
        }
    }
}

int LCA(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    ///根据差距倍增上跳
    while (dep[u] >  dep[v])
        u = f[u][ lg[dep[u] - dep[v]] - 1];
    if (u == v) return u;
    for (int i = lg[dep[u]] - 1; i >= 0; -- i) {
        if (f[u][i] != f[v][i])
            u = f[u][i], v = f[v][i];
    }
    return f[u][0];
}

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

int query(int u, int v) {
    int _lca = LCA(u, v);
    //cout << _lca << endl;
    return dep[u] + dep[v] - 2 * dep[_lca];
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n-1; ++ i) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    init();
    BFS(1);
    scanf("%d", &m);
    while (m--) {
        int x, y, u, v, k;
        scanf("%d%d%d%d%d", &x, &y, &u, &v, &k);
        int flag = 0;
        ///u - v
        int ans1 = query(u, v);
        if (ans1 <= k && (k - ans1) % 2 == 0) {
            flag = 1;
        }
        ///u - x - y - v
        int ans2 = query(u, x) + query(y, v) + 1;
        if (ans2 <= k && (k - ans2) % 2 == 0) {
            flag = 1;
        }
        ///u - y - x - v
        int ans3 = query(u, y) + query(x, v) + 1;
        if (ans3 <= k && (k - ans3) % 2 == 0) {
            flag = 1;
        }
        //cout << ans1 << " " << ans2 << " " << ans3 << endl;
        if (flag) puts("YES");
        else puts("NO");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Vikyanite/p/15087541.html