P6348 [PA2011]Journeys
题目描述
一个星球上有 n 个国家和许多双向道路,国家用 \(1\sim n\) 编号。
但是道路实在太多了,不能用通常的方法表示。于是我们以如下方式表示道路:\((a,b),(c,d)\)表示,对于任意两个国家 \(x,y\),如果 \(a\le x\le b,c\le y\le d\),那么在 \(x,y\) 之间有一条道路。
首都位于 P 号国家。你想知道 P 号国家到任意一个国家最少需要经过几条道路。保证 P 号国家能到任意一个国家。
输入格式
第一行三个整数 n,m,P。
之后 m 行,每行 44 个整数 a,b,c,d。
输出格式
n 行,第 i 行表示 P 号国家到第 i 个国家最少需要经过几条路。
输入输出样例
输入 #1复制
5 3 4
1 2 4 5
5 5 4 4
1 1 3 3
输出 #1复制
1
1
2
0
1
说明/提示
对于所有测试点,保证 \(1\le n\le 5\times 10^5 ,1\le m\le 10^5,1\le a\le b\le n,1\le c\le d\le n\)。
同样都是线段树优化建图。
不同之处在于,此处建图为区间到区间,不能起始区间和终点区间都按照线段树分解后两两建边。因为这样建边的数量还是比较多的,所以应该增加一点,所有的起始区间点向这个新增点建边,然后新增点向终点区间点建边。
由于是无向边,所以要建两条!
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e6;
const int maxm=4e7;
int n,m,p;
struct edge
{
int u,v,w,nxt;
}e[maxm];
int head[maxn],js;
void addage(int u,int v,int w)
{
e[++js].v=v;e[js].u=u;e[js].w=w;
e[js].nxt=head[u];head[u]=js;
}
int cnt;
int lc[maxn],rc[maxn],rootin,rootout;
void buildin(int &cur,int l,int r)
{
if(l==r)
{
cur=l;
return ;
}
cur=++cnt;
int mid=(l+r)>>1;
buildin(lc[cur],l,mid);
buildin(rc[cur],mid+1,r);
addage(lc[cur],cur,0);
addage(rc[cur],cur,0);
}
void buildout(int &cur,int l,int r)
{
if(l==r)
{
cur=l;
return ;
}
cur=++cnt;
int mid=(l+r)>>1;
buildout(lc[cur],l,mid);
buildout(rc[cur],mid+1,r);
addage(cur,lc[cur],0);
addage(cur,rc[cur],0);
}
void updat(int cur,int l,int r,int ql,int qr,int p,int tp)
{
if(ql<=l&&r<=qr)
{
if(tp==0)addage(cur,p,0);
else addage(p,cur,1);
return;
}
int mid=(l+r)>>1;
if(ql<=mid)updat(lc[cur],l,mid,ql,qr,p,tp);
if(mid<qr)updat(rc[cur],mid+1,r,ql,qr,p,tp);
}
int dis[maxn];
bool inq[maxn];
deque<int>q;
void spfa(int s)
{
memset(dis,0x3f,sizeof dis);
dis[s]=0;
q.push_front(s);inq[s]=1;
while(!q.empty())
{
int u=q.front();q.pop_front();inq[u]=0;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(!inq[v])
{
inq[v]=1;
if(dis[v]<=dis[q.front()])q.push_front(v);
else q.push_back(v);
}
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&p);
cnt=n;
buildin(rootin,1,n);
buildout(rootout,1,n);
while(m--)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
++cnt;
updat(rootin,1,n,a,b,cnt,0);
updat(rootout,1,n,c,d,cnt,1);
++cnt;
updat(rootin,1,n,c,d,cnt,0);
updat(rootout,1,n,a,b,cnt,1);
}
spfa(p);
for(int i=1;i<=n;++i)printf("%d\n",dis[i]);
return 0;
}