VIrtuoso

两把多兰剑加个布甲鞋

导航

Educational Codeforces Round 51 F. The Shortest Statement(lca+最短路)

https://codeforces.com/contest/1051/problem/F

题意

给一个带权联通无向图,n个点,m条边,q个询问,询问两点之间的最短路
其中 m-n<=20,1<=n,m<=1e5

思路

  • 因为图一定联通,所以n-1<=m<=n+20
  • 因为是求任意两点的最短路,所以直接暴力跑最短路是不行的,考虑选择性的跑最短路
  • 因为是求两点之间的距离,所以可以往lca方面想
  • 先跑一棵生成树出来,然后处理出每个点的lca,这样就可以求出任意两点的距离
  • 然后就可以记录下剩下的边,因为剩下的边会影响经过连接的两个点的最短路,那么可以对这些边的两个点跑一次dij
  • 然后对于没次查询的两个点

    ans=min(d[u]+d[v]-2*d[lca(u,v)],min(d[1tot][u]+d[1tot][v]))

#include<bits/stdc++.h>
#define ll long long
#define mk make_pair
#define ft first
#define se second
#define pb push_back
#define M 100005
#define inf 1e15
#define pii pair<ll,int>
using namespace std;
vector<pii>g[M];
int E[M],vi[M],f[M][30],D[M],inq[M];
ll dp[M],d[50][M];
int n,m,u,v,w,i,q,tot=0;
ll ans;

void dfs(int u,int fa){
    vi[u]=1;
    f[u][0]=fa;for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i].se;ll w=g[u][i].ft;if(v==fa)continue;
        if(!vi[v]){
            D[v]=D[u]+1;dp[v]=dp[u]+w;
            dfs(v,u);
        }else{
            E[tot++]=u;E[tot++]=v;
        }
    }
    return ;
}

void dj(int id,int st){
    priority_queue<pii,vector<pii>,greater<pii> >Q;
    Q.push(mk(0,st));
    for(int i=1;i<=n;i++){d[id][i]=inf;inq[i]=0;}
    d[id][st]=0;
    while(!Q.empty()){
        int u=Q.top().se;Q.pop();
        if(inq[u])continue;
        inq[u]=1;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i].se;ll w=g[u][i].ft;
            if(d[id][v]>d[id][u]+w){
                d[id][v]=d[id][u]+w;
                Q.push(mk(d[id][v],v));
            }
        }
    }
}

int lca(int u,int v){
    if(D[v]>D[u])swap(u,v);
    
    int dis=D[u]-D[v];
    for(int i=20;i>=0;i--)if(dis&(1<<i))u=f[u][i];
    
    if(u==v)return u;

    for(int i=20;i>=0;i--)
        if(f[u][i]!=f[v][i]){u=f[u][i];v=f[v][i];}
    return f[u][0];
}
int main(){
    cin>>n>>m;
    for(i=0;i<m;i++){
        scanf("%d%d%d",&u,&v,&w);
        g[u].pb(mk(w,v));
        g[v].pb(mk(w,u));
    }
    dfs(1,0);
    sort(E,E+tot);tot=unique(E,E+tot)-E;
    for(i=0;i<tot;i++)dj(i,E[i]);

    cin>>q;
    while(q--){
        scanf("%d%d",&u,&v);
        ans=dp[u]+dp[v]-2*dp[lca(u,v)];
        for(i=0;i<tot;i++)
            ans=min(ans,d[i][u]+d[i][v]);
        printf("%lld\n",ans);
    }
}


posted on 2018-11-19 20:05  VIrtuoso  阅读(110)  评论(0编辑  收藏  举报