第十四届蓝桥杯省赛CB-景区导游
景区导游
题目
思路
这一题有\(n\)个点,还有\(n-1\)条无向边,每条边有一个权值,这个信息告诉我们,这其实就是树结构
并且给了\(K\)个点,让我们按照顺序带游客游览
但是现在让我们选择\(K-1\)个点,并且顺序游览
现在要求对\(K\)个点跳过任意一个,计算跳过这个点,游览完需要花费多少时间
(1) 我们需要注意的是,如何计算两个点\((u, v)\)距离:
- 首先确定一个根节点\(root\)
- 计算\(root -> u\)和\(root -> v\)的距离,但是重复计算了一段\(2 * root -> lca(u, v)\)
- 因此\(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;
}

浙公网安备 33010602011771号