第十四届蓝桥杯省赛CB-景区导游

景区导游

题目

link

思路

这一题有\(n\)个点,还有\(n-1\)条无向边,每条边有一个权值,这个信息告诉我们,这其实就是树结构

并且给了\(K\)个点,让我们按照顺序带游客游览

但是现在让我们选择\(K-1\)个点,并且顺序游览

现在要求对\(K\)个点跳过任意一个,计算跳过这个点,游览完需要花费多少时间

(1) 我们需要注意的是,如何计算两个点\((u, v)\)距离:

  1. 首先确定一个根节点\(root\)
  2. 计算\(root -> u\)\(root -> v\)的距离,但是重复计算了一段\(2 * root -> lca(u, v)\)
  3. 因此\(dist(u, v) = dist[u] + dist[v] - dist[lca(u, v)]\)

(2) 另一个难点在于,我们要先把整个\(K\)个点的完整花费时间算出来,然后我们再挨个去除某个点的值

例如\(a -> b -> c\),现在要把b去除,则\(sum - dist[a, b] - dist[b, c] + dist[a, c]\)

#include <bits/stdc++.h>
#define pb push_back
#define int long long
#define SZ(v) (int)(v.size())
using namespace std;
const int N = 1e5+10;
int _;

int n, k;
int u, v, t;
int fa[N][30], dep[N];
vector<int> e[N], w[N];
int path[N], dist[N];

void dfs(int u, int father) {
    dep[u] = dep[father] + 1;
    fa[u][0] = father;
    for(int i = 1; i <= 20; i++) {
        fa[u][i] = fa[fa[u][i-1]][i-1];
    }
    for(int i = 0; i < SZ(e[u]); i++) {
        int v = e[u][i], ww = w[u][i];
        if(v == father) continue;
        dist[v] = dist[u] + ww;
        dfs(v, u);
    }
}

int LCA(int u, int v) {
    if(dep[u] < dep[v]) {
        swap(u, v);
    }
    for(int i = 20; i >= 0; i--) {
        if(dep[fa[u][i]] >= dep[v]) {
            u = fa[u][i];
        }
    }
    if(u == v) return u;
    for(int i = 20; i >= 0; i--) {
        if(fa[u][i] != fa[v][i]) {
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}   

int get_dist(int u, int v) {
    if(u == 0 || v == 0) return 0;
    return dist[u] + dist[v] - 2 * dist[LCA(u, v)];
}

void solve() {
    cin >> n >> k;
    for(int i = 1; i < n; i++) {
        cin >> u >> v >> t;
        e[u].pb(v); e[v].pb(u);
        w[u].pb(t); w[v].pb(t);
    }
    dfs(1, 0);
    int sum = 0;
    for(int i = 1; i <= k; i++) {
        cin >> path[i];
        sum += get_dist(path[i], path[i-1]);
    }

    // a -> b -> c
    // b去掉: sum - [a, b] - [b, c] + [a, c];
    for(int i = 1; i <= k; i++) {  
        int dis1 = get_dist(path[i], path[i-1]);
        int dis2 = get_dist(path[i], path[i+1]);
        int dis3 = get_dist(path[i-1], path[i+1]);
        int ans = sum - dis1 - dis2 + dis3;
        cout << ans << " ";
    }
}

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

    _ = 1;
    // cin >> _;
    
    while(_--) {
        solve();
    } 
    return 0;
}
posted @ 2025-03-21 23:44  Evan619  阅读(32)  评论(0)    收藏  举报