蓝桥杯2023年第十四届省赛真题-景区导游

354 阅读2分钟

题目描述

某景区一共有 N 个景点,编号 1 到 N。景点之间共有 N − 1 条双向的摆渡车线路相连,形成一棵树状结构。在景点之间往返只能通过这些摆渡车进行,需要花费一定的时间。 小明是这个景区的资深导游,他每天都要按固定顺序带客人游览其中 K 个景点:A1, A2, . . . , AK。今天由于时间原因,小明决定跳过其中一个景点,只带游客按顺序游览其中 K − 1 个景点。具体来说,如果小明选择跳过 Ai,那么他会按顺序带游客游览 A1, A2, . . . , Ai−1, Ai+1, . . . , AK, (1 ≤ i ≤ K)。 请你对任意一个 Ai,计算如果跳过这个景点,小明需要花费多少时间在景点之间的摆渡车上?

输入格式

第一行包含 2 个整数 N 和 K。 以下 N − 1 行,每行包含 3 个整数 u, v 和 t,代表景点 u 和 v 之间有摆渡车线路,花费 t 个单位时间。 最后一行包含 K 个整数 A1, A2, . . . , AK 代表原定游览线路。

解法

这题看上去是比较经典的板子题Kruscal重构树加Lca, 我们先使用最小生成树算法构成一个图然后我们每次的运动就是在这颗树上活动所以点i, j的最短距离就是他们到他们的最近公共祖先的距离之和

Code

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define int long long
#define endl '\n'
#define pb push_back
#define NO cout << "NO" << endl;
#define YES cout << "YES" << endl;
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<VI> VII;
const int N = 2e5 + 10;
void solve()
{
    int n, k; cin >> n >> k;
    vector<vector<PII>> e(n + 1);
    vector<array<int, 3>> a(n - 1);
    for (auto &[u, v, w] : a) cin >> u >> v >> w;
    sort(all(a), [] (array<int, 3> a, array<int, 3> b) {
        return a[2] < b[2];
    });
    VI fx(n + 1); rep (i, 1, n) fx[i] = i;
    function<int(int)> find = [&] (int x) {
        return fx[x] == x ? fx[x] : fx[x] = find(fx[x]);
    };
    for (auto [u, v, w] : a) {
        int fa = find(u), fb = find(v);
        if (fa != fb) {
            fx[fa] = fb;
            e[u].pb({v, w});
            e[v].pb({u, w});
        }
    }
    VII f(n + 1, VI(30)), s(n + 1, VI(30)), p(n + 1, VI(30));
    VI de(n + 1), dis(n + 1);
    function<void(int, int, int)> dfs = [&] (int u, int Fa, int x) {
        f[u][0] = Fa;
        s[u][0] = x;
        dis[u] = dis[Fa] + x;
        de[u] = de[Fa] + 1;
        for (auto [v, w] : e[u]) {
            if (v != Fa) dfs(v, u, w);
        }
    };   
    dfs(1, 0, 0);
    // rep (i, 1, n) cout << dis[i] << " \n"[i==n];
    rep (j, 1, 20) rep (i, 1, n) {
        f[i][j] = f[f[i][j-1]][j - 1];
    }
    function<ll(int, int)> Lca = [&] (int x, int y) -> ll {
    if (de[x] < de[y]) swap(x, y);
    per (i, 0, 20) if (de[f[x][i]] >= de[y]) x = f[x][i];
    if (x == y) return x;
    per (i, 0, 20) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0]; 
    };
    VI b(k + 1); rep (i, 1, k) cin >> b[i];
    ll res = 0;
    auto get = [&] (int i, int j) {
        return dis[i] + dis[j] - 2 * dis[Lca(i, j)];
    };
    rep (i, 1, k - 1) res += get(b[i], b[i + 1]);
    cout << res -  get(b[1], b[2]) << ' ';
    rep (i, 2, k - 1) cout << res - get(b[i], b[i + 1]) + get(b[i-1], b[i + 1]) - get(b[i], b[i - 1]) << ' ';
    cout << res - get(b[k], b[k - 1]) << endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    // int T;cin >> T;
    // while ( T -- )
    solve();
    return 0;
}