cumtoj修建道路 LCA倍增
题目描述
个点条边,点之间两两连通,每次询问个点,求使这个点连通的最小花费。()
因为给的是一颗树,最终的答案就是
倍增求lca即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#define ll long long
#define mem(a, x) memset(a,x,sizeof(a))
#define iosup ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int N = 1e5 + 10;
int fa[N][1 << 5];
int n, q, dep[N];
ll dis[N];
struct Edge {
int v, w;
};
vector<Edge> G[N];
void dfs(int u, int father) {
fa[u][0] = father;
for (int i = 1; i <= 20; i++)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (Edge &e:G[u])
if (e.v != father) {
dis[e.v] = dis[u] + e.w;
dep[e.v] = dep[u] + 1;
dfs(e.v, u);
}
}
inline void init() {
scanf("%d%d", &n, &q);
int u, v, c;
for (int i = 1; i < n; i++) {
scanf("%d%d%d", &u, &v, &c);
G[u].push_back(Edge{v, c});
G[v].push_back(Edge{u, c});
}
dis[1] = dep[1] = 0;
dfs(1, 0);
}
int lca(int u,int v){
if (dep[u]>dep[v]) std::swap(u,v);
int k = dep[v] - dep[u];
for(int i=20;i>=0;i--){
if((k>>i) & 1)
v = fa[v][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];
}
ll d(int u,int v){
return dis[u] + dis[v] - 2*dis[lca(u,v)];
}
int main() {
init();
int x, y, z;
for (int i = 1; i <= q; i++) {
scanf("%d%d%d", &x, &y, &z);
printf("%lld\n",(d(x,y)+d(y,z)+d(x,z)) >> 1);
}
return 0;
}
浙公网安备 33010602011771号