复习一下线段树优化建图:
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;
}