【JZOJ5287】【NOIP2017提高A组模拟8.16】最短路

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

我被坑了,他的环是指一个边双联通分量……
我们若处理出起点到每个点的最短距离d,那么若询问x,y的lca不在一个环上,那么答案显然是d[x]+d[y]-2*d[lca],那么若lca在环上呢?我们处理出起点到每个点的在dfs树上的距离deep[x]和每个边双的长度len,那么显然环上两个点x,y的最小距离即min(|deep[x]-deep[y]|,len-|deep[x]-deep[y]|)。若询问u,v刚走进lca所在环的点分别为x,y,那么答案即d[u]+d[v]-d[x]-d[y]+min(|deep[x]-deep[y]|,len-|deep[x]-deep[y]|).现在问题的关键转化为如何求x,y。我们将一个边双除顶点以外的点都连向顶点,那么在求u,v的lca时倍增到只差一步重合的时候那两个点即所求的x,y。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=4e5+5;
int first[maxn],last[maxn],next[maxn],d[maxn],deep[maxn],value[maxn],bz[maxn];
int n,m,q,i,t,j,k,l,x,y,z,num,ln,xx,yy,num1,low[maxn],ans;
int f[maxn][20],fa[maxn],len[maxn],dis[maxn],bz1[maxn],p[maxn],id[maxn],dfn[maxn];
void lian(int x,int y,int z){
    last[++num]=y;next[num]=first[x];first[x]=num;value[num]=z;id[num]=i;
}
void dg(int x,int y){
    int t;bz[x]=1;p[++p[0]]=x;dfn[x]=low[x]=++num1;
    for (t=first[x];t;t=next[t]){
        if (id[t]==y) continue;
        if (bz[last[t]]==2){
            if (fa[last[t]]==x) len[bz1[last[t]]]+=value[t];
            continue;
        }else if (!bz[last[t]]){
            d[last[t]]=d[x]+value[t];
            dg(last[t],id[t]);
            if (low[last[t]]>=dfn[x]){
                if (p[p[0]]!=last[t]){
                    ++num;len[num]=d[p[p[0]]]-d[x];
                    while (p[p[0]]!=x) f[p[p[0]]][0]=x,bz1[p[p[0]]]=num,fa[p[p[0]]]=x,bz[p[p[0]--]]=2;
                }else p[0]--;
            }
        }
        low[x]=min(low[x],low[last[t]]);
    }
}
void dg1(int x){
    int t;bz[x]=1;
    for (t=first[x];t;t=next[t]){
        if (bz[last[t]]) continue;
        if (fa[last[t]]) k=d[last[t]]-d[fa[last[t]]],dis[last[t]]=dis[fa[last[t]]]+min(len[bz1[last[t]]]-k,k),deep[last[t]]=deep[fa[last[t]]]+1;
        else bz1[last[t]]=++num,f[last[t]][0]=x,dis[last[t]]=dis[x]+value[t],deep[last[t]]=deep[x]+1;
        dg1(last[t]);
    }
}
int main(){
//  freopen("data.in","r",stdin);freopen("data.out","w",stdout);
    scanf("%d%d%d",&n,&m,&q);
    for (i=1;i<=m;i++)
        scanf("%d%d%d",&x,&y,&z),lian(x,y,z),lian(y,x,z);
    num=0;dg(1,0);memset(bz,0,sizeof(bz));
    dg1(1);
    ln=log(num)/log(2);
    for (j=1;j<=ln;j++)
        for (i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    deep[0]=-1;
    for (i=1;i<=q;i++){
        scanf("%d%d",&x,&y);xx=x;yy=y;
        if (deep[x]<deep[y]) swap(x,y);
        for (j=ln;j>=0;j--)
            if (deep[f[x][j]]>=deep[y]) x=f[x][j];
        if (x==y) ans=dis[xx]+dis[yy]-2*dis[y],printf("%d\n",ans);
        else{
            if (bz1[x]==bz1[y]) ans=dis[xx]+dis[yy]-dis[x]-dis[y]+min(abs(d[x]-d[y]),len[bz1[x]]-abs(d[x]-d[y])),printf("%d\n",ans);
            else{
                for (j=ln;j>=0;j--)
                    if (bz1[f[x][j]]!=bz1[f[y][j]]) x=f[x][j],y=f[y][j];
                x=f[x][0];y=f[y][0];
                ans=dis[xx]+dis[yy]-dis[x]-dis[y]+min(abs(d[x]-d[y]),len[bz1[x]]-abs(d[x]-d[y]));
                printf("%d\n",ans);
            }
        }
    }
}
发布了257 篇原创文章 · 获赞 451 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/crybymyself/article/details/77488957
今日推荐