【题意】给了一颗树,问加一条边可以为两点节省多少距离?
【解题方法】知道dp[u,v]=dp[u]+dp[v]-2*dp[lca(u,v)]就没问题啦。
【AC 代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100010;
int n,q,a,b,l;
int head[maxn],tot,dp[maxn],p[18][maxn],dep[maxn];
struct edge{
int v,w,next;
}E[maxn<<2];
void init(){
memset(head,-1,sizeof(head));tot=0;
}
void addedge(int u,int v,int w){
E[tot].v=v,E[tot].w=w,E[tot].next=head[u],head[u]=tot++;
}
void dfs(int u,int f,int c,int d)
{
dep[u]=d;
p[0][u]=f;
dp[u]=c;
for(int i=head[u]; ~i; i=E[i].next){
int v=E[i].v;
if(v==f) continue;
dfs(v,u,c+E[i].w,d+1);
}
}
void build()
{
dfs(1,-1,0,0);
for(int i=0; i+1<18; i++){
for(int v=1; v<=n; v++){
if(p[i][v]<0) p[i+1][v] = -1;
else p[i+1][v]=p[i][p[i][v]];
}
}
}
int lca(int u,int v)
{
if(dep[u]>dep[v]) swap(u,v);
for(int i=0; i<18; i++){
if(dep[v]-dep[u]>>i&1) v=p[i][v];
}
if(u==v) return u;
for(int i=17; i>=0; i--){
if(p[i][u]!=p[i][v]){
u=p[i][u];
v=p[i][v];
}
}
return p[0][u];
}
int main()
{
int T,cas=1;
int u,v,w;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d",&n,&q);
for(int i=1; i<n; i++){
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
build();
scanf("%d%d%d",&a,&b,&l);
printf("Case #%d:\n",cas++);
while(q--)
{
scanf("%d%d",&u,&v);
int _lca=lca(u,v);
int uv = dp[u]+dp[v]-2*dp[_lca];
int ua = dp[u]+dp[a]-2*dp[lca(u,a)];
int ub = dp[u]+dp[b]-2*dp[lca(u,b)];
int av = dp[a]+dp[v]-2*dp[lca(a,v)];
int bv = dp[b]+dp[v]-2*dp[lca(b,v)];
int ans = max(0,uv-min(ua+bv,ub+av)-l);
printf("%d\n",ans);
}
}
return 0;
}