zoukankan      html  css  js  c++  java
  • HDU5669 Road 分层最短路+线段树建图

    分析:(官方题解)

    首先考虑暴力,显然可以直接每次O(n^2)

    ​的连边,最后跑一次分层图最短路就行了.

    然后我们考虑优化一下这个连边的过程 ,因为都是区间上的操作,所以能够很明显的想到利用线段树来维护整个图,

    连边时候找到对应区间,把线段树的节点之间连边.这样可以大大缩减边的规模,然后再跑分层图最短路就可以了.

    但是这样建图,每一次加边都要在O(logn)个线段树节点上加边,虽然跑的非常快,但是复杂度仍然是不科学的.

    为了解决边的规模的问题,开两棵线段树,连边时候可以新建一个中间节点,在对应区间的节点和中间节点之间连边

    进一步缩减了边的规模,强行下降一个数量级

    最后跑一下分层图最短路就行了

    复杂度O(mlog^2n)

    什么你会线段树但是不会分层图最短路?安利JLOI2011飞行路线.

    因为边的数目还是相对比较多的,所以不能使用SPFA,而要使用Heap-Dijkstra来做最短路,

    但是不排除某些厉害的选手有特殊的SPFA姿势可以做或者普通 SPFA写的比较优美就不小心跑过去了...

    注:出题人的题解写的很详细了,然后JLOI2011飞行路线是BZOJ2763 直接去做就好了

          然后我的建图刚开始不太完善,跑了600+ms,然后后来完善了一下,按线段树节点建图(这就是题解)

         不过每个线段树的节点不需要和它的区域内所有的点连边,只需要按照线段树的结构,连它的左右儿子就行了

    代码:

    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <string.h>
    using namespace std;
    typedef long long LL;
    const int INF=0x3f3f3f3f;
    const int N=5e4+1;
    int d[11][N*10+20],head[N*10+20],tot,n,m,k;
    struct Edge{
      int v,w,next;
    };
    vector<Edge>edge;
    void add(int u,int v,int w){
      edge.push_back(Edge{v,w,head[u]});
      head[u]=edge.size()-1;
    }
    struct Node{
      int cur,v,dis;
      bool operator<(const Node &rhs)const{
        return dis>rhs.dis;
      }
    };
    priority_queue<Node>q;
    bool vis[11][N*10+20];
    int dij(){
      memset(d,INF,sizeof(d));
      memset(vis,0,sizeof(vis));
      d[0][8*N+1]=0;
      q.push(Node{0,8*N+1,0});
      while(!q.empty()){
        int cur=q.top().cur,u=q.top().v;
        q.pop();
        if(vis[cur][u])continue;
        vis[cur][u]=1;
        for(int i=head[u];~i;i=edge[i].next){
           int v=edge[i].v;
           if(!vis[cur][v]&&d[cur][v]>d[cur][u]+edge[i].w){
            d[cur][v]=d[cur][u]+edge[i].w;
            q.push(Node{cur,v,d[cur][v]});
           }
           if(cur+1>k)continue;
           if(!vis[cur+1][v]&&d[cur+1][v]>d[cur][u]){
             d[cur+1][v]=d[cur][u];
             q.push(Node{cur+1,v,d[cur+1][v]});
           }
        }
      }
      return d[k][8*N+n]==INF?-1:d[k][8*N+n];
    }
    void build(int rt,int l,int r){
      if(l==r){
        add(N*8+l,rt,0);
        add(rt+4*N,N*8+l,0);
        return;
      }
      int mid=(l+r)>>1;
      build(rt<<1,l,mid);
      build(rt<<1|1,mid+1,r);
      add(rt<<1,rt,0),add(rt<<1|1,rt,0);
      add(rt+4*N,4*N+rt*2,0),add(rt+4*N,4*N+rt*2+1,0);
    }
    int now,w;
    void treeadd1(int rt,int l,int r,int x,int y){
       if(x<=l&&r<=y){
          add(rt,now,w);
          return;
       }
       int mid=(l+r)>>1;
       if(x<=mid)treeadd1(rt<<1,l,mid,x,y);
       if(y>mid)treeadd1(rt<<1|1,mid+1,r,x,y);
    }
    void treeadd2(int rt,int l,int r,int x,int y){
       if(x<=l&&r<=y){
          add(now,rt+4*N,0);
          return;
       }
       int mid=(l+r)>>1;
       if(x<=mid)treeadd2(rt<<1,l,mid,x,y);
       if(y>mid)treeadd2(rt<<1|1,mid+1,r,x,y);
    }
    int main(){
      scanf("%d%d%d%d",&n,&n,&m,&k);
      memset(head,-1,sizeof(head));
      edge.clear();
      build(1,1,n);
      now=9*N;
      for(int i=1;i<=m;++i){
        int a,b,c,d;
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&w);
        ++now;
        treeadd1(1,1,n,a,b);
        treeadd2(1,1,n,c,d);
        ++now;
        treeadd1(1,1,n,c,d);
        treeadd2(1,1,n,a,b);
      }
      int ans=dij();
      if(ans==-1)printf("CreationAugust is a sb!
    ");
      else printf("%d
    ",ans);
      return 0;
    }
    View Code
  • 相关阅读:
    git merge merge错误 —— 纠正
    copy —— docker cp & kubectl cp
    docker —— 获取 仓库中的 tag 列表
    课程——《深度学习的优化方法》
    基础知识篇(干货,次次都有新体悟)——十大经典排序算法2
    基础知识篇(干货,次次都有新体悟)——数据结构
    criteo 接口升级——MAPI deprecated
    CAP
    Redis 数据类型
    十大经典排序算法(转发)
  • 原文地址:https://www.cnblogs.com/shuguangzw/p/5414874.html
Copyright © 2011-2022 走看看