题意:给你一颗顶点数为n的树,然后再给出一条边,连接这棵树的两个顶点。然后有q条询问,每条询问给出两个点a、b,问从a-b走最后给出的边是否能节省路程,若能则输出节省的路程,若不能输出0。
这道题之前做过,今天看的时候发现用lca写起来会非常简单,唉, 当时还不会lca,要不就不会写的那么麻烦了……
这题将其简化,那么就是个求树上两点距离的问题。首先,询问给出的两个点u、v这两个点在树上的距离是ans1,这两个点通过给出的边所要走的距离是ans2,那么如果ans1>ans2,那么说明能节省路程,否则不能节省路程。ans1好算,用w[i]表示根节点到i的距离,那么只要计算出anc=lca(u,v),u-v的距离就为w[u]+w[v]-2*w[anc]。至于ans2,这个也好办,只要在这两条路径中选一个最短的就行:u-x-y-v,v-x-y-u,其中x、y是给出的边连接的两个顶点,x-y的距离就是该边的权值。
这么写的话虽然时间上比之前得方法要慢一些,但是写起来非常容易,思路也很清晰,不容易出错。
之前写的本本题题解:http://blog.csdn.net/qian99/article/details/8918058
代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
const int maxn=100000+10;
const int dep=17;
struct Edge
{
int v,dist;
};
vector<Edge>edges;
vector<int>G[maxn];
int d[maxn],w[maxn],fa[maxn][dep+1];
bool vis[maxn];
void clearAll(int n)
{
for(int i=0;i<=n;++i) G[i].clear();
edges.clear();
memset(fa,0,sizeof(fa));
memset(vis,0,sizeof(vis));
}
void AddEdges(int u,int v,int dist)
{
edges.push_back((Edge){v,dist});
edges.push_back((Edge){u,dist});
int m=edges.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}
void bfs(int s,int n)
{
d[s]=0;w[s]=0;
queue<int>q;
q.push(s);
Edge e;
while(!q.empty())
{
int u=q.front();q.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=0;i<G[u].size();++i)
{
e=edges[G[u][i]];
if(!vis[e.v])
{
d[e.v]=d[u]+1;
w[e.v]=w[u]+e.dist;
fa[e.v][0]=u;
q.push(e.v);
}
}
}
for(int i=1;i<=dep;++i)
for(int j=1;j<=n;++j)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
int lca(int x,int y)
{
if(x==y) return x;
if(d[x]>d[y]) swap(x,y);
for(int i=dep;i>=0;--i)
if(d[fa[y][i]]>d[x]) y=fa[y][i];
if(fa[y][0]==x) return x;
if(d[y]>d[x]) y=fa[y][0];
for(int i=dep;i>=0;--i)
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t,tcase=0;
scanf("%d",&t);
int n,q;
while(t--)
{
tcase++;
scanf("%d%d",&n,&q);
clearAll(n);
int x,y,z;
for(int i=0;i<n-1;++i)
{
scanf("%d%d%d",&x,&y,&z);
AddEdges(x,y,z);
}
bfs(1,n);
scanf("%d%d%d",&x,&y,&z);
printf("Case #%d:\n",tcase);
int u,v,anc,anc2,ans1,ans2;
while(q--)
{
scanf("%d%d",&u,&v);
anc=lca(u,v);
ans1=w[u]+w[v]-2*w[anc];
anc=lca(u,x);
anc2=lca(v,y);
ans2=w[u]+w[x]-2*w[anc]+w[v]+w[y]-2*w[anc2]+z;
anc=lca(u,y);
anc2=lca(v,x);
ans2=min(ans2,w[u]+w[y]-2*w[anc]+w[v]+w[x]-2*w[anc2]+z);
if(ans1>ans2) ans1=ans1-ans2;
else ans1=0;
printf("%d\n",ans1);
}
}
return 0;
}