“蔚来杯“2022牛客暑期多校训练营3 C、A

这篇博客主要介绍了两个C++编程问题的解决方案。一是使用排序和位运算优化读取速度,二是解决树的最近公共祖先(LCA)问题,涉及前缀LCA和后缀LCA的预处理及动态计算。文章提供了AC代码示例,展示了如何在删除特定关键点后,比较两棵树剩余部分的LCA点权大小。
摘要由CSDN通过智能技术生成

C

直接sort排序,用&加快读取速度即可

AC代码:

#include <bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<n;i++)
using namespace std;
using LL = long long;

bool cmp(string &a, string &b) {
    return a + b < b + a;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;
    vector<string> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    sort(a.begin(), a.end(), cmp);
    for (int i = 0; i < n; i++) {
        cout << a[i];
    }
    cout << '\n';

    return 0;
}

Ancestor

题目大意是给定两棵树,每个点都有各自的点权,给出k个关键点,删除某一个关键点以后,A树的剩下所有关键点的LCA的点权大于B树剩下所有关键点的LCA的点权的个数

一种思路:枚举每个关键点,假设它就是被删除的,求剩下的所有关键点的LCA,可知LCA可以累积计算,所以先预处理出两棵树各自的前缀LCA和后缀LCA,最后枚举k个关键点,这时只需要求前缀LCA和后缀LCA去掉这个点以后的LCA即可

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int n, k, z[100010];
struct Tree {
    int f[100010][25], dep[100010], pre[100010], suf[100010];
    vector<int> G[100010];
    void init() {
        dfs(1, 0);
        for (int i = 1; i <= k; i++) {
            if (i == 1) {
                pre[i] = z[i];
            } else {
                pre[i] = lca(pre[i - 1], z[i]);
            }
        }
        for (int i = k; i >= 1; i--) {
            if (i == k) {
                suf[i] = z[i];
            } else {
                suf[i] = lca(suf[i + 1], z[i]);
            }
        }
    }
    void dfs(int u, int fa) {
        dep[u] = dep[fa] + 1;
        f[u][0] = fa;
        for (int i = 1; (1 << i) < dep[u]; i++) {
            f[u][i] = f[f[u][i - 1]][i - 1];
        }
        for (auto v : G[u]) {
            if (v != fa) {
                dfs(v, u);
            }
        }
    }
    int lca(int x, int y) {
        if (dep[x] > dep[y]) {
            swap(x, y);
        }
        for (int i = 20; i >= 0; i--) {
            if (dep[x] <= dep[y] - (1 << i)) {
                y = f[y][i];
            }
        }
        if (x == y) {
            return x;
        }
        for (int i = 20; i >= 0; i--) {
            if (f[x][i] == f[y][i]) {
                continue;
            }
            x = f[x][i];
            y = f[y][i];
        }
        return f[x][0];
    }
}a, b;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> k;
    for (int i = 1; i <= k; i++) {
        cin >> z[i];
    }
    vector<int> x(n + 1), y(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> x[i];
    }
    for (int i = 2; i <= n; i++) {
        int fa;
        cin >> fa;
        a.G[fa].push_back(i);
        a.G[i].push_back(fa);
    }
    for (int i = 1; i <= n; i++) {
        cin >> y[i];
    }
    for (int i = 2; i <= n; i++) {
        int fa;
        cin >> fa;
        b.G[fa].push_back(i);
        b.G[i].push_back(fa);
    }
    a.init();
    b.init();
    int ans = 0;
    for (int i = 1; i <= k; i++) {
        if (i == 1) {
            if (x[a.suf[i + 1]] > y[b.suf[i + 1]]) {
                ans++;
            }
        } else if (i == k) {
            if (x[a.pre[i - 1]] > y[b.pre[i - 1]]) {
                ans++;
            }
        } else {
            if (x[a.lca(a.pre[i - 1], a.suf[i + 1])] > y[b.lca(b.pre[i - 1], b.suf[i + 1])]) {
                ans++;
            }
        }
    }
    cout << ans << '\n';
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值