lanqiao3516 景区导游(LCA)
This commit is contained in:
91
14lanqiao/test9-2.cpp
Normal file
91
14lanqiao/test9-2.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/* lanqiao3516 景区导游(LCA)
|
||||||
|
|
||||||
|
LCA-最近公共祖先
|
||||||
|
比如原本的遍历顺序是 a->b->c, 总路径长度为sum,若要跳过b,则新的路径长度为
|
||||||
|
sum-d(a,b)-d(b,c)+d(a,c)
|
||||||
|
其中 d(a,b)、d(b,c)、d(a,c)使用LCA求解更快
|
||||||
|
若要求u->v的路径长度, 等于求u-> root + v -> root - 2*(root->LCA(u ,v))
|
||||||
|
即分别从u和v走到根结点,再减去2倍的根结点到 (u,v) 的最近公共祖先的路径长度
|
||||||
|
倍增法求LCA时间复杂度-O(nlogn),单次LCA查询时间复杂度-O(1ogn),k次查询时间复杂度-O(klogn)
|
||||||
|
总时间复杂度O((n+k)1ogn)由于n,k同級,该算法时间复杂度为O(nlogn)
|
||||||
|
*/
|
||||||
|
#include<bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
#define int long long
|
||||||
|
const int N = 1e5 + 10;
|
||||||
|
int n, k;
|
||||||
|
|
||||||
|
// 邻接表存图
|
||||||
|
vector<pair<int, int>> g[N];
|
||||||
|
int deep[N]; // 深度数组
|
||||||
|
int fa[N][21]; // 倍增数组, fa[i][j]表示从i节点开始跳2^j步可到达的节点
|
||||||
|
int p[N]; // 原始的游览路线
|
||||||
|
int d[N]; // d[i]存储i到根节点的距离
|
||||||
|
|
||||||
|
// 预处理深度数组
|
||||||
|
void dfs(int u, int father){
|
||||||
|
deep[u] = deep[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 < g[u].size(); i++){
|
||||||
|
int v = g[u][i].first, w = g[u][i].second;
|
||||||
|
if(v == father) continue;
|
||||||
|
d[v] = d[u] + w;
|
||||||
|
dfs(v, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 倍增求LCA模版
|
||||||
|
int LCA(int x, int y){
|
||||||
|
if(deep[x] < deep[y]) swap(x, y);
|
||||||
|
for(int i = 20; i >= 0; i--){
|
||||||
|
if(deep[fa[x][i]] >= deep[y]){
|
||||||
|
x = fa[x][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(x == y) return x;
|
||||||
|
for(int i = 20; i >= 0; i--){
|
||||||
|
if(fa[x][i] != fa[y][i]){
|
||||||
|
x = fa[x][i], y = fa[y][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fa[x][0];
|
||||||
|
}
|
||||||
|
// 计算x和y的距离
|
||||||
|
int calc(int x, int y){
|
||||||
|
if(x == 0 || y == 0) return 0;
|
||||||
|
return d[x] + d[y] - 2*d[LCA(x, y)];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
signed main(){
|
||||||
|
cin >> n >> k;
|
||||||
|
for(int i = 1; i < n; i++){
|
||||||
|
int u, v, w; cin >> u >> v >> w;
|
||||||
|
g[u].push_back({v, w});
|
||||||
|
g[v].push_back({u, w});
|
||||||
|
}
|
||||||
|
dfs(1, 0);
|
||||||
|
int sum = 0;
|
||||||
|
for(int i = 1; i <= k; i++){
|
||||||
|
cin >> p[i];
|
||||||
|
sum += calc(p[i], p[i-1]);
|
||||||
|
}
|
||||||
|
for(int i = 1; i <= k; i++){ // 循环枚举去除第i个节点
|
||||||
|
int d1 = calc(p[i], p[i-1]);
|
||||||
|
int d2 = calc(p[i], p[i+1]);
|
||||||
|
int d3 = calc(p[i-1], p[i+1]);
|
||||||
|
cout << sum - d1 - d2 + d3 << " ";
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* test sanples -> 10 7 13 14
|
||||||
|
6 4
|
||||||
|
1 2 1
|
||||||
|
1 3 1
|
||||||
|
3 4 2
|
||||||
|
3 5 2
|
||||||
|
4 6 3
|
||||||
|
2 6 5 1
|
||||||
|
*/
|
||||||
Reference in New Issue
Block a user