zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
    }
    
    
    
  • 相关阅读:
    收集一些dos网络配置命令,从新获取ip刷新dns
    多个线程访问共享对象和数据的方式
    Oracle rownum 分页, 排序
    ORACLE中用rownum分页并排序的SQL语句
    CentOS 6.5安装MongoDB 2.6(多yum数据源)
    【编程练习】收集的一些c++代码片,算法排序,读文件,写日志,快速求积分等等
    java枚举使用详解
    PHP+MySQL动态网站开发从入门到精通(视频教学版)
    Premiere Pro CS6标准教程
    黑客攻防:实战加密与解密
  • 原文地址:https://www.cnblogs.com/VIrtu0s0/p/9985209.html
Copyright © 2011-2022 走看看