• [CF1051F]The Shortest Statement (LCA+最短路)(给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路)


    题目:给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路

    n100000,m≤100000,m-n20.

    首先看到m-n20这条限制,我们可以想到是围绕这个20来做这道题。

    即如果我们随便在图上找一棵树,有最多21条非树边,连接最多42个顶点

    考虑两点x,yx,y之间的最短路就是某个点到xx和yy的最短路之和

    首先对于只走树边的情况,这个点是两点的LCA

    如果经过非树边,xx或yy到枚举的这个点的最短路上的最后一条边一定是非树边(如果都是树边的话完全可以转化到一个连接着非树边的点上去)

    然后对于所有连接非树边的点都跑一遍最短路,询问时直接枚举这些点取min即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #define M 200010
    #define int long long
    using namespace std;
    int read()
    {
        char ch=getchar();int x=0;
        while(ch>'9'||ch<'0') ch=getchar();
        while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    struct point{
        int to,next,dis;
    }e[M<<1];
    int n,m,num,Q,top;
    int q[M],head[M],deep[M],dist[M];
    int dis[50][M],fa[M][25];
    bool vis[M];
    struct node{int id,dis;};
    bool operator < (node a1,node a2) {return a1.dis>a2.dis;}
    void add(int from,int to,int dis)
    {
        e[++num].next=head[from];
        e[num].to=to;
        e[num].dis=dis;
        head[from]=num;
    }
    void dfs(int x,int f)
    {
        vis[x]=true; fa[x][0]=f;
        for(int i=head[x];i;i=e[i].next)
        {
            int to=e[i].to;
            if(to==f) continue;
            if(vis[to]) q[++top]=x,q[++top]=to;
            else
            {
                deep[to]=deep[x]+1;
                dist[to]=dist[x]+e[i].dis;
                dfs(to,x);
            }
        }
    }
    int lca(int x,int y)
    {
        if(deep[x]<deep[y]) swap(x,y);
        for(int i=19;i>=0;i--)
            if(deep[fa[x][i]]>=deep[y])
                x=fa[x][i];
        if(x==y) return x;
        for(int i=19;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    void Dijkstra(int id)
    {
        memset(dis[id],63,sizeof(dis[id]));
        memset(vis,false,sizeof(vis));
        priority_queue<node>Q;
        dis[id][q[id]]=0;
        Q.push((node){q[id],0});
        while(!Q.empty())
        {
            int x=Q.top().id;Q.pop();
            if(vis[x]) continue;
            vis[x]=true;
            for(int i=head[x];i;i=e[i].next)
            {
                int to=e[i].to;
                if(!vis[to]&&dis[id][x]+e[i].dis<dis[id][to])
                {
                    dis[id][to]=dis[id][x]+e[i].dis;
                    Q.push((node){to,dis[id][to]});
                }
            }
        }
    }
    #undef int
    int main()
    {
        #define int long long
        n=read(); m=read();
        for(int i=1;i<=m;i++)
        {
            int a=read(),b=read(),c=read();
            add(a,b,c); add(b,a,c);
        }
        deep[1]=1;dfs(1,0);
        for(int j=1;j<=19;j++)
            for(int i=1;i<=n;i++)
                fa[i][j]=fa[fa[i][j-1]][j-1];
        sort(q+1,q+1+top); top=unique(q+1,q+1+top)-q-1;
        for(int i=1;i<=top;i++) Dijkstra(i);
        Q=read();
        while(Q--)
        {
            int x=read(),y=read();
            int ans=dist[x]+dist[y]-2*dist[lca(x,y)];
            for(int i=1;i<=top;i++) ans=min(ans,dis[i][x]+dis[i][y]);
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    四月十五号日报
    四月十一号日报
    四月八号日报
    五月六号日报
    CCSUOJ评测系统——第四次scrum冲刺
    CCSUOJ评测系统——第三次scrum冲刺
    CCSUOJ评测系统——第二次scrum冲刺
    C# Process 进程管理
    [C#][收集整理]
    [C#][收集整理]
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9699224.html
Copyright © 2020-2023  润新知