• BZOJ3073 [Pa2011]Journeys[最短路—线段树优化建边]


    新技能get✔。

    线段树优化建边主要是针对一类连续区间和连续区间之间建边的题,建边非常的优秀。。


    这题中,每次要求$[l1,r1]$每一点向$[l2,r2]$每一点建无向边,然后单元最短路。


    暴力建边,边数$O(n^2m)$,时空双炸。

    优化一点的建边,对于一个区间的点,把他们统一向一个虚点连零边,再从这个虚点向另一个区间每一个点连一条带权边。这样,每一条路径都是可以通过这个来表示的。边数$O(nm)$,仍然不行。

    然后,采用线段树的优秀的“将区间拆分成不超过$log n$个小区间”的性质,对于$n$个点,建两颗线段树$A,B$,$A$称作入树,$B$称作出树。他们的叶子就是所有的$n$个点,上面的非叶点就是区间。。(先假设是单向的边)然后,对于一次区间向另一区间的连边,从出树$B$拆分出来的对应的$log n$个区间代表的点分别向一个新开的虚点连一条有向0边,再从这个虚点向入树$A$对应的另一个区间拆分的若干小区间点连带权边,这样实现了区间连边。但是,这只是区间整体连边了,还要保证点与点连通,只要把出树$B$每个点从孩子向父亲连有向0边,入树$A$每个点从父亲向孩子连有向0边,就表示一个点通过“爬”到一个区间点,走过虚点,在下来走到另外一个目标点这样一个过程。最后,走进入树后,为了可以继续走,从$A$向$B$的每一个代表相同区间的点连0边,表示再过去。

    有一个dalao的图可能会解释的非常清晰。。附上地址

    线段树优化建边大致就是这个原理。然后直接从底层叶子开始为源点跑dij就行了。

    然后个人觉得很多代码很繁。。偶尔看到一种写法,对每个点编一个号,把AB两树底层叶子编号直接合并成一个,省去了两树之间的相互建边。。这样码量就小很多了。具体还是看代码。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=5e5+7;
    24 int n,m,s,cnt;
    25 struct thxorz{
    26     int head[N*5],nxt[N*21],to[N*21],w[N*21],tot;
    27     inline void add(int x,int y,int z){to[++tot]=y,nxt[tot]=head[x],head[x]=tot,w[tot]=z;}
    28 }G;
    29 struct SGT{
    30     int id[N<<2];
    31     #define lc i<<1
    32     #define rc i<<1|1
    33     void build(int i,int L,int R,int dir){
    34         if(L==R){id[i]=L;return;}
    35         id[i]=++cnt;int mid=L+R>>1;//dbg2(i,cnt),dbg2(L,R);
    36         build(lc,L,mid,dir),build(rc,mid+1,R,dir);
    37         if(!dir)G.add(id[i],id[lc],0),G.add(id[i],id[rc],0);
    38         else G.add(id[lc],id[i],0),G.add(id[rc],id[i],0);
    39     }
    40     void update(int i,int L,int R,int ql,int qr,int dir){
    41         if(ql<=L&&qr>=R){dir?G.add(cnt,id[i],1):G.add(id[i],cnt,0);return;}
    42         int mid=L+R>>1;
    43         if(ql<=mid)update(lc,L,mid,ql,qr,dir);
    44         if(qr>mid)update(rc,mid+1,R,ql,qr,dir);
    45     }
    46 }A,B;
    47 priority_queue<pii,vector<pii>,greater<pii> > pq;
    48 int dis[N*5];
    49 #define y G.to[j]
    50 inline void dij(){
    51     memset(dis,0x3f,sizeof dis);pq.push(make_pair(dis[s]=0,s));
    52     while(!pq.empty()){
    53         int d=pq.top().first,x=pq.top().second;pq.pop();
    54         if(dis[x]^d)continue;
    55         for(register int j=G.head[x];j;j=G.nxt[j])if(MIN(dis[y],d+G.w[j]))pq.push(make_pair(dis[y],y));
    56     }
    57 }
    58 #undef y
    59 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    60     cnt=read(n),read(m),read(s);
    61     A.build(1,1,n,0),B.build(1,1,n,1);
    62     for(register int i=1,l1,r1,l2,r2;i<=m;++i){
    63         read(l1),read(r1),read(l2),read(r2);
    64         ++cnt,B.update(1,1,n,l2,r2,0),A.update(1,1,n,l1,r1,1);
    65         ++cnt,B.update(1,1,n,l1,r1,0),A.update(1,1,n,l2,r2,1);
    66     }
    67     dij();
    68     for(register int i=1;i<=n;++i)printf("%d
    ",dis[i]);
    69     return 0;
    70 }
    View Code

    不过,这题鉴于全是0/1边,所以直接一个0/1BFS就可以线性解决了。。并没有快多少可能是deque的锅。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=5e5+7;
    24 int n,m,s,cnt;
    25 struct thxorz{
    26     int head[N*5],nxt[N*21],to[N*21],w[N*21],tot;
    27     inline void add(int x,int y,int z){to[++tot]=y,nxt[tot]=head[x],head[x]=tot,w[tot]=z;}
    28 }G;
    29 struct SGT{
    30     int id[N<<2];
    31     #define lc i<<1
    32     #define rc i<<1|1
    33     void build(int i,int L,int R,int dir){
    34         if(L==R){id[i]=L;return;}
    35         id[i]=++cnt;int mid=L+R>>1;//dbg2(i,cnt),dbg2(L,R);
    36         build(lc,L,mid,dir),build(rc,mid+1,R,dir);
    37         if(!dir)G.add(id[i],id[lc],0),G.add(id[i],id[rc],0);
    38         else G.add(id[lc],id[i],0),G.add(id[rc],id[i],0);
    39     }
    40     void update(int i,int L,int R,int ql,int qr,int dir){
    41         if(ql<=L&&qr>=R){dir?G.add(cnt,id[i],1):G.add(id[i],cnt,0);return;}
    42         int mid=L+R>>1;
    43         if(ql<=mid)update(lc,L,mid,ql,qr,dir);
    44         if(qr>mid)update(rc,mid+1,R,ql,qr,dir);
    45     }
    46 }A,B;
    47 deque<pii> q;
    48 int dis[N*5];
    49 #define y G.to[j]
    50 inline void dij(){
    51     memset(dis,0x3f,sizeof dis);q.push_back(make_pair(dis[s]=0,s));
    52     while(!q.empty()){
    53         int d=q.front().first,x=q.front().second;q.pop_front();
    54         if(d^dis[x])continue;
    55         for(register int j=G.head[x];j;j=G.nxt[j])if(MIN(dis[y],d+G.w[j]))
    56             G.w[j]?q.push_back(make_pair(dis[y],y)):q.push_front(make_pair(dis[y],y));
    57     }
    58 }
    59 #undef y
    60 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    61     cnt=read(n),read(m),read(s);
    62     A.build(1,1,n,0),B.build(1,1,n,1);
    63     for(register int i=1,l1,r1,l2,r2;i<=m;++i){
    64         read(l1),read(r1),read(l2),read(r2);
    65         ++cnt,B.update(1,1,n,l2,r2,0),A.update(1,1,n,l1,r1,1);
    66         ++cnt,B.update(1,1,n,l1,r1,0),A.update(1,1,n,l2,r2,1);
    67     }
    68     dij();
    69     for(register int i=1;i<=n;++i)printf("%d
    ",dis[i]);
    70     return 0;
    71 }
    View Code

    总结:区间建边,线段树。。

  • 相关阅读:
    Spring Data MongoDB 一:入门篇(环境搭建、简单的CRUD操作)
    如何大幅提升web前端性能之看tengine在大公司架构实践
    SSM+redis整合(mybatis整合redis做二级缓存)
    Spring中报"Could not resolve placeholder"的解决方案(引入多个properties文件)
    Windows下安装Redis并注册为服务
    关于Local System/Local Service/Network Service账户
    在Windows下将Redis注册为本地服务
    Windows服务已经标记为删除
    SpringBoot集成MyBatis的分页插件PageHelper
    【Tomcat】Tomcat下设置项目为默认项目
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11768182.html
Copyright © 2020-2023  润新知