Codeforces-GYM(101808):Another Shortest Path Problem(思维+LCA)

K. Another Shortest Path Problem
time limit per test
3.0 s
memory limit per test
256 MB
input
standard input
output
standard output

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.

Input

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 uivi, 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.

Output

For each test case, and for each query, print one line containing one integer, the shortest path between X and Y.

Example
input
Copy
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
output
Copy
5
16
6

思路:可以发现题目中的n个点其实是一棵树(n-1条边)里额外加了一条边而已。如果没有那条额外的边,那么任意2点间的最短距离是确定了的。加了那条额外的边后,可能可以利用这条边使距离更小。

设那条额外的边的2个端点分别为x,y,边的权重为zdis(a,b)表示a,b在树上的最短距离。

那么对于2个点a,b,那么ab间的最短距离肯定是:

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;
}



猜你喜欢

转载自blog.csdn.net/mitsuha_/article/details/80629479