https://codeforces.com/gym/101808/problem/K
/* 这道题当板子去学了,挑战上的板子,加了个权值
在一棵没有环的树上,每个节点肯定有其父亲节点和祖先节点,而最近公共祖先,就是两个节点在这棵树上深度最大的公共的祖先节点。
换句话说,就是两个点在这棵树上距离最近的公共祖先节点。
所以LCA主要是用来处理当两个点仅有唯一一条确定的最短路径时的路径。 */
题意:n个点n个边的带权无向图,q次查询,问你任意两点间的最短距离
题解:倍增LCA,这样想:
1.把图拆一条边,被变成一棵树跑LCA,拆边后可以利用dfs预处理每个点到根节点1的距离dis,
2.树上任意两点间的距离等于而树上任意两点a,b的距离 len=dis[a]+dis[b]-2*dis[LCA(a,b)]
3.由于拆了一条边,在把那条边考虑是就可以了
int u,v;
cin>>u>>v;
int ans=get_dis(u,v);
ans=min(ans,get_dis(xx,u)+get_dis(yy,v)+zz);//xx,yy,为拆的那条边
ans=min(ans,get_dis(xx,v)+get_dis(yy,u)+zz);
cout<<ans<<endl;
代码如下:
/*
对于一颗树,我们可以dfs预处理处每个节点 i 到1号节点的距离dis[i]
而树上任意两点a,b的距离len=dis[a]+dis[b]-2*dis[LCA(a,b)]
*/
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<vector>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
#define P pair<int,int>
int par[60][100005*2];//j这个点向上跳2^i个的结点
int dep[100005*2];//深度
long long dis[100005*2];//该结点到根节点1的距离
vector<P> G[100005*2];
int MAXK;//能跳到的步数 2^k
int root;
void dfs(int v,int p,int d){
par[0][v]=p;//v这个节点向上跳2^0个就是p
dep[v]=d;
for(int i=0;i<G[v].size();i++){
if(G[v][i].second!=p){
dis[G[v][i].second]=dis[v]+G[v][i].first; //更新距离
dfs(G[v][i].second,v,d+1);
}
}
}
void init(int V){
dfs(root,-1,0);
for(int k=0;k+1<MAXK;k++){
for(int v=1;v<=V;v++){
if(par[k][v]==-1) par[k+1][v]=-1;
else par[k+1][v]=par[k][par[k][v]];
}
}
}
int lca(int u,int v){
if(dep[u]>dep[v]) //保证每次都是可以从最深的点往上跳
swap(u,v);
for(int k=0;k<MAXK;k++){
if( (dep[v]-dep[u]) >> k & 1){//相当于二进制枚举是1的位置
v=par[k][v];
}
}
if(u==v)
return u;
for(int k=MAXK-1;k>=0;k--){
if(par[k][u]!=par[k][v]){//不是同一层
u=par[k][u];
v=par[k][v];
}
}
return par[0][u];
}
long long get_dis(int u,int v){
return dis[u]+dis[v]-2*dis[lca(u,v)];
}
int main(){
int t;
cin>>t;
while(t--){
root=1;
MAXK=32;//最大跳跃的2^K
int N,Q;
cin>>N>>Q;
for(int i=1;i<=100005*2;i++)//注意
G[i].clear();
for(int i=0;i<N-1;i++){
int x,y,z;
cin>>x>>y>>z;
G[x].push_back(P(z,y));//无向图带权值
G[y].push_back(P(z,x));
}
int xx,yy,zz;//无向图拆一条边变成树
cin>>xx>>yy>>zz;
init(N);
for(int i=0;i<Q;i++){
int u,v;
cin>>u>>v;
long long ans=get_dis(u,v);
ans=min(ans,get_dis(xx,u)+get_dis(yy,v)+zz);
ans=min(ans,get_dis(xx,v)+get_dis(yy,u)+zz);
cout<<ans<<endl;
}
}
}