BZOJ2125 最短路

原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2125

最短路

Description

给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。

Input

输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w 最后Q行,每行两个整数v,u表示一组询问

Output

输出Q行,每行一个整数表示询问的答案

Sample Input

9 10 2
1 2 1
1 4 1
3 4 1
2 3 1
3 7 1
7 8 2
7 9 2
1 5 3
1 6 4
5 6 1
1 9
5 7

Sample Output

5
6

HINT

对于100%的数据,N<=10000,Q<=10000

题解

哈哈我也是做过仙人掌的人啦。

其实这是一道非常板的题,我们先将仙人掌建成一棵圆方树:

图片1.png

对于一个环,新建一个方点,与环上的圆点连接,边的权值为圆点与深度最浅的圆点的距离。

图片2.png

这个操作可以通过魔改的 T a r j a n 来完成,正常的树边直接连即可。

建完图以后就可以使用树上的套路了,一发 d f s 下去统计离根的距离,顺便得到倍增数组(貌似圆方树必须要倍增 L C A ,表示很气)。

现在我们就得到了一棵树,根据普通树的套路,点 x 与点 y 的距离便为 d i s x + d i s y 2 × d i s l c a ( x , y )

但这可是棵圆方树啊,怎么能跟普通的树一样呢?

上述式子只有在 l c a ( x , y ) 为圆点时成立,当 f = l c a ( x , y ) 为方点时,设 t x f x 走一步的点,同理 t y f y 走一步得到的点,最终的答案为 d i s x + d i s y d i s t x d i s t y + d i s ( t x , t y ) d i s ( t x , t y ) t x , t y 在仙人掌环上的距离。

代码

代码非常简短。

#include<bits/stdc++.h>
using namespace std;
const int M=2e4+5;
struct sd{int to,len;};
int n,m,q,df,tot,dfn[M],low[M],dad[M],val[M],S[M],id[M],dep[M],J[M][21],dis[M],tx,ty;
vector<sd>mmp[M],T[M];
void loop(int f,int t,int w)
{
    int pre=w,cot=0,i;
    for(i=t;i!=dad[f];i=dad[i])S[i]=pre,pre+=val[i],id[i]=cot++;
    S[++tot]=S[f];S[f]=0;
    for(i=t;i!=dad[f];i=dad[i])T[tot].push_back((sd){i,min(S[tot]-S[i],S[i])}),T[i].push_back((sd){tot,min(S[tot]-S[i],S[i])});
}
void tarjan(int v,int f)
{
    dfn[v]=low[v]=++df;dad[v]=f;int to;
    for(int i=mmp[v].size()-1;i>=0;--i)
    {
        to=mmp[v][i].to;if(to==f)continue;
        if(!dfn[to])val[to]=mmp[v][i].len,tarjan(to,v),low[v]=min(low[v],low[to]);
        else low[v]=min(low[v],dfn[to]);
        if(low[to]>dfn[v])T[v].push_back((sd){to,mmp[v][i].len});
    }
    for(int i=mmp[v].size()-1;i>=0;--i)
    {
        to=mmp[v][i].to;
        if(dad[to]!=v&&dfn[to]>dfn[v])loop(v,to,mmp[v][i].len);
    }
}
void dfs(int v,int f,int d,int l)
{
    dep[v]=d,dis[v]=l,J[v][0]=f;int to;
    for(int i=1;(1<<i)<=d;++i)J[v][i]=J[J[v][i-1]][i-1];
    for(int i=T[v].size()-1;i>=0;--i)
    {
        to=T[v][i].to;if(to==f)continue;
        dfs(to,v,d+1,l+T[v][i].len);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);int d=dep[x]-dep[y];
    for(int i=0;(1<<i)<=d;++i)if(d&(1<<i))x=J[x][i];
    if(x==y)return x;
    for(int i=20;i>=0;--i)if((1<<i)<=dep[x]&&J[x][i]!=J[y][i])x=J[x][i],y=J[y][i];
    tx=x;ty=y;
    return J[x][0];
}
void in()
{
    int a,b,c;scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=m;++i)scanf("%d%d%d",&a,&b,&c),mmp[a].push_back((sd){b,c}),mmp[b].push_back((sd){a,c});
}
void ac()
{
    tot=n;tarjan(1,0);dfs(1,0,1,0);
    int x,y,f,ans;
    while(q--)
    {
        scanf("%d%d",&x,&y);f=lca(x,y);
        if(f<=n)printf("%d\n",dis[x]+dis[y]-2*dis[f]);
        else
        {
            ans=dis[x]-dis[tx]+dis[y]-dis[ty];
            if(id[tx]<id[ty])ans+=min(S[tx]+S[f]-S[ty],S[ty]-S[tx]);
            else ans+=min(S[ty]+S[f]-S[tx],S[tx]-S[ty]);
            printf("%d\n",ans);
        }
    }
}
int main(){in();ac();}

猜你喜欢

转载自blog.csdn.net/shadypi/article/details/81148707