BZOJ 3073: [Pa2011]Journeys Dijkstra+线段树优化建图
复习一下线段树优化建图:
1.两颗线段树的叶子节点的编号是公用的.
2.每次连边是要建两个虚拟节点 $p1,p2$ 并在 $p1,p2$ 之间连边.
#include <bits/stdc++.h> #define N 8000034 #define ls t[x].lson #define rs t[x].rson #define inf 1000000000 #define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout) using namespace std; int edges,tot,n,m,s,rtin,rtout; int hd[N],to[N],nex[N],val[N],d[N],done[N]; void addedge(int u,int v,int c) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; } int newnode() { return ++tot; } struct Node { int lson,rson; }t[N]; struct P { int u,dis; P(int u=0,int dis=0):u(u),dis(dis){} bool operator<(P b) const { return b.dis<dis; } }; priority_queue<P>q; namespace segin { void build(int l,int r,int &x) { if(l==r) { x=l; return; } else { x=newnode(); } int mid=(l+r)>>1; if(l<=mid) build(l,mid,ls),addedge(x,ls,0); if(r>mid) build(mid+1,r,rs),addedge(x,rs,0); } void Add(int l,int r,int x,int L,int R,int p) { if(l>=L&&r<=R) { addedge(p,x,0); return; } int mid=(l+r)>>1; if(L<=mid) Add(l,mid,ls,L,R,p); if(R>mid) Add(mid+1,r,rs,L,R,p); } }; namespace segout { void build(int l,int r,int &x) { if(l==r) { x=l; return; } else { x=newnode(); } int mid=(l+r)>>1; if(l<=mid) build(l,mid,ls),addedge(ls,x,0); if(r>mid) build(mid+1,r,rs),addedge(rs,x,0); } void Add(int l,int r,int x,int L,int R,int p) { if(l>=L&&r<=R) { addedge(x,p,0); return; } int mid=(l+r)>>1; if(L<=mid) Add(l,mid,ls,L,R,p); if(R>mid) Add(mid+1,r,rs,L,R,p); } }; void Add(int l1,int r1,int l2,int r2,int w) { int p1=newnode(),p2=newnode(); addedge(p1,p2,w); segout::Add(1,n,rtout,l1,r1,p1); segin::Add(1,n,rtin,l2,r2,p2); } void Dijkstra() { for(int i=0;i<N;++i) d[i]=inf; for(d[s]=0,q.push(P(s,0));!q.empty();) { P e=q.top(); q.pop(); int u=e.u; if(done[u]) continue; done[u]=1; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(d[v]>d[u]+val[i]) { d[v]=d[u]+val[i]; q.push(P(v,d[v])); } } } } int main() { int i,j; // setIO("input"); scanf("%d%d%d",&n,&m,&s); tot=n; segin::build(1,n,rtin); segout::build(1,n,rtout); for(i=1;i<=m;++i) { int l1,r1,l2,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2); Add(l1,r1,l2,r2,1); Add(l2,r2,l1,r1,1); } Dijkstra(); for(i=1;i<=n;++i) printf("%d\n",d[i]); return 0; }