• 思维训练——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;
    }
  • 相关阅读:
    NeiHappy我相信做技术也能身体好
    陈皓程序员技术练级攻略
    张子阳对人生的一点看法
    HaoyuTan程序员之路──C语言
    三种冒泡排序的实现与时间快慢的比较
    R语言——中文分词包jiebaR
    任务计划程序执行bat失败
    R语言︱文本挖掘之中文分词包——Rwordseg包(原理、功能、详解)
    R+NLP︱text2vec包——四类文本挖掘相似性指标 RWMD、cosine、Jaccard 、Euclidean
    R语言做文本挖掘 Part5情感分析
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/15087541.html
Copyright © 2020-2023  润新知