zoukankan      html  css  js  c++  java
  • CF1051F The Shortest Statement

    题意简化

    给你一个有n个点,m条边的无向连通图。 有q次询问,第i次询问回答从ui到di的最短路的长度。
    (1<=q,n,m<=10^5, 0<=m-n<=20)

    题解

    这题比起普通的Floyd板子题多了一个限制 0<=m-n<=20, 而这个限制就是突破口

    边数比点数多了不超过20, 这不就相当于在一颗树上连了一些非树边吗(好像所有联通图都可以这样解释)

    首先考虑只经过树边的情况,这也就是求树上两点之间的最短路,LCA一下就好了
    然后考虑非树边,既然非树边只有二十条
    所以我们可以直接暴力求出每根非树边的两端点为起点的单源最短路
    然后对于每次询问暴力查询一遍经过该端点的结果就行了
    其实就是强行CSP图论算法大综合

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    #define ll long long
    #define in inline
    #define get getchar()
    in int read()
    {
        int t=0; char ch=get;
        while(ch<'0' || ch>'9') ch=get;
        while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
        return t;
    }
    const int _=2e5+6;
    struct edge1{
        int x,y,w;
    }ed[_];
    struct edge{
        int to,ne,w;
    }e[_];
    int n,m,fa[_],flag[_],tot,h[_];
    in int find(int x)
    {
        if(fa[x]==x) return x;
        fa[x]=find(fa[x]);
        return fa[x];
    }
    in int cmp(edge1 a,edge1 b) {return a.w==b.w?a.x<b.x:a.w<b.w;}
    in void add(int x,int y,int z)
    {
        e[++tot].to=y,e[tot].ne=h[x],e[tot].w=z,h[x]=tot;
    }
    in void kruskal()
    {
        for(re int i=1;i<=n;i++) fa[i]=i;
        sort(ed+1,ed+m+1,cmp);
        for(re int i=1;i<=m;i++) {
            int fx=find(ed[i].x),fy=find(ed[i].y);
            if(fx!=fy) {
                fa[fx]=fy;
                add(ed[i].x,ed[i].y,ed[i].w);
                add(ed[i].y,ed[i].x,ed[i].w);
            }
            else
                flag[i]=1;
        }
    }
    int vis[_],f[_][25],cnt,dep[_];
    ll d[_],dis[50][_];
    in void dfs(int u)
    {
        vis[u]=1;
        for(re int i=h[u];i;i=e[i].ne) {
            int v=e[i].to;
            if(!vis[v]&&v!=u){
            f[v][0]=u;
            d[v]=d[u]+e[i].w;
            dep[v]=dep[u]+1;
            dfs(v);}
        }
    }
    in void prepare()
    {
        dep[1]=1;
        dfs(1);
        for(re int j=1;j<=20;j++)
            for(re int i=1;i<=n;i++)
                f[i][j]=f[f[i][j-1]][j-1];
    }
    in void dijkstra(int k,int rt)
    {
        memset(vis,0,sizeof(vis));
        dis[k][rt]=0;
        priority_queue<pair<ll,int > >q;
        q.push(make_pair(0,rt));
        while(!q.empty())
        {
            int u=q.top().second;q.pop();
            if(vis[u])continue;
            vis[u]=1;
            for(re int i=h[u];i;i=e[i].ne)
            {
                int v=e[i].to;
                if(dis[k][v]>dis[k][u]+e[i].w)
                {
                    dis[k][v]=dis[k][u]+e[i].w;
                    q.push(make_pair(-dis[k][v],v));
                }
            }
        }
    }
    in void work()
    {
        for(re int i=1;i<=m;i++)
            if(flag[i]==1)
                add(ed[i].x,ed[i].y,ed[i].w), add(ed[i].y,ed[i].x,ed[i].w); //先把非树边加入新图
        for(re int i=1;i<=m;i++)    {
            if(flag[i]) {
                dijkstra(++cnt,ed[i].x);    //每个端点跑dijkstra
                dijkstra(++cnt,ed[i].y);    
            }
        }
    }
    in int lca(int x,int y)
    {
        
        if(dep[x]>dep[y]) swap(y,x);
        for(re int i=20;i>=0;i--)
            if(dep[f[y][i]]>=dep[x])y=f[y][i];
        if(x==y) return x;
        for(re int i=20;i>=0;i--)
            if(f[y][i]!=f[x][i]) y=f[y][i], x=f[x][i];
        return f[x][0];
    }
    in void get_ans()
    {
        int q=read();
        for(re int i=1;i<=q;i++) {
            int x=read(),y=read();
            int k=lca(x,y); //求出LCA
            ll ans=d[x]-2*d[k]+d[y];//求树上距离
            for(re int j=1;j<=cnt;j++)
                ans=min(dis[j][x]+dis[j][y],ans); //枚举每种经过非树边端点的情况
            printf("%lld
    ",ans);
        }
    }
    int main()
    {
        memset(dis,0x7f,sizeof(dis));
        n=read(),m=read();
        for( re int i=1;i<=m;i++) ed[i].x=read(),ed[i].y=read(),ed[i].w=read();
        kruskal(); //kruskal建树
        prepare();//LCA的预处理
        work();// 对于每条非树边跑最短路
        get_ans();//在线查询
        return 0;
    }
    
  • 相关阅读:
    ArcGIS超级工具SPTOOLS-制图篇
    ArcGIS超级工具SPTOOLS-MXD操作篇
    ArcGIS超级工具SPTOOLS-影像的批量裁剪和批量合并
    Get Raster Properties获得栅格的信息
    ArcGIS超级工具SPTOOLS-按属性裁剪,矢量数据批量裁剪,矢量数据批量合库
    ArcGIS超级工具SPTOOLS-SHP转数据库,批量数据库转数据库,栅格彩色转黑白
    ArcGIS超级工具SPTOOLS-锐角检查,获得内角并判断是否凸多边形,获得线(面)两个折点方向
    ArcGIS超级工具SPTOOLS-线封闭,点集转面
    ArcGIS超级工具-征地部标准坐标导出导入 SPTOOLS
    arcgis的arcpy写入几何怎么创建一个空心面要素并读取几何和属性信息,根本不够管
  • 原文地址:https://www.cnblogs.com/yzhx/p/11749298.html
Copyright © 2011-2022 走看看