Shortest path problems have always been a part of competitive programming, appearing in many contests all around the world. In order to keep that tradition, we created another one:
You are given an undirected connected weighted graph with N nodes and N edges, and you have to answer Q queries. Each query consists of two nodes X and Y, and you have to find the length of the shortest path between nodes X and Y.
The first line contains a single integer T, the number of test cases.
Each test case starts with a line containing two integers N and Q, the number of nodes (and edges) and the number of queries. (3 ≤ N ≤ 105) (1 ≤ Q ≤ 105)
Each of the following N lines contain the description of the edges. The ith line contains 3 space-separated integers ui, vi, and wi. This means that there is an undirected edge between nodes ui and vi, with a weight of wi. (1 ≤ ui, vi ≤ N) (1 ≤ wi ≤ 105)
Then Q lines follow, the ith line contains two integers X and Y. This means that you need to find the shortest path between nodes X and Y. (1 ≤ X, Y ≤ N)
It is guaranteed that the graph contains no self loops or multiple edges.
For each test case, and for each query, print one line containing one integer, the shortest path between X and Y.
1 6 3 1 2 2 1 3 4 2 6 3 3 4 1 3 5 10 3 6 6 1 4 2 5 3 2
5 16 6
思路:可以发现题目中的n个点其实是一棵树(n-1条边)里额外加了一条边而已。如果没有那条额外的边,那么任意2点间的最短距离是确定了的。加了那条额外的边后,可能可以利用这条边使距离更小。
设那条额外的边的2个端点分别为x,y,边的权重为z。dis(a,b)表示a,b在树上的最短距离。
那么对于2个点a,b,那么a和b间的最短距离肯定是:
min(dis(a,b),dis(a,x)+dis(b,x),dis(a,y)+dis(b,y))或
min(dis(a,x)+dis(b,y)+z,dis(a,y)+dis(b,x)+z);
那么剩下的就是求dis(a,b)了。
设d[x]表示x到根节点的距离。
那么dis(a,b)=d[a]+d[b]-2*d[LCA(a,b)]。
其中d[x]可以预处理一下,然后就是求LCA了。(我这里是用线段树求的LCA)
#include<bits/stdc++.h> using namespace std; const int MAX=2e5+10; const int MOD=1e9+7; const double PI=acos(-1.0); typedef long long ll; int tot,dp[MAX],L[MAX],num[MAX]; ll d[MAX]; vector<pair<int,int> >e[MAX]; void dfs(int k,int fa,int dep) { dp[k]=dep; L[k]=tot; num[tot++]=k; for(int i=0;i<e[k].size();i++) { pair<int,int>nex=e[k][i]; if(nex.first==fa)continue; d[nex.first]=d[k]+nex.second; dfs(nex.first,k,dep+1); num[tot++]=k; } } struct lenka { int l,r,an; }A[MAX<<2]; void build(int k,int l,int r) { A[k].l=l,A[k].r=r; if(l==r){A[k].an=num[r];return;} build(2*k,l,(l+r)/2); build(2*k+1,(l+r)/2+1,r); if(dp[A[2*k].an]>dp[A[2*k+1].an])A[k].an=A[2*k+1].an; else A[k].an=A[2*k].an; } int LCA(int k,int x,int y) { if(x==A[k].l&&y==A[k].r)return A[k].an; if(y<=A[2*k].r)return LCA(2*k,x,y); if(x>=A[2*k+1].l)return LCA(2*k+1,x,y); int l=LCA(2*k,x,A[2*k].r); int r=LCA(2*k+1,A[2*k+1].l,y); return (dp[l]>dp[r])?r:l; } int main() { int T; cin>>T; while(T--) { int n,q; scanf("%d%d",&n,&q); for(int i=1;i<=n;i++)e[i].clear(); int X,Y,Z; for(int i=1;i<n;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); e[x].push_back({y,z}); e[y].push_back({x,z}); } scanf("%d%d%d",&X,&Y,&Z); tot=0; dfs(1,0,0); build(1,0,tot-1); while(q--) { int x,y; scanf("%d%d",&x,&y); int xx=LCA(1,min(L[x],L[X]),max(L[x],L[X])); int yy=LCA(1,min(L[y],L[Y]),max(L[y],L[Y])); int xy=LCA(1,min(L[x],L[Y]),max(L[x],L[Y])); int yx=LCA(1,min(L[y],L[X]),max(L[y],L[X])); int z=LCA(1,min(L[x],L[y]),max(L[x],L[y])); ll ans=d[x]+d[y]-2*d[z]; ans=min(ans,(d[x]+d[X]-2*d[xx])+(d[y]+d[X]-2*d[yx])); ans=min(ans,(d[x]+d[Y]-2*d[xy])+(d[y]+d[Y]-2*d[yy])); ans=min(ans,(d[x]+d[Y]-2*d[xy])+(d[y]+d[X]-2*d[yx])+Z); ans=min(ans,(d[x]+d[X]-2*d[xx])+(d[y]+d[Y]-2*d[yy])+Z); printf("%lld\n",ans); } } return 0; }