题目描述
Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路。N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路。Seter保证一条道路不会修建两次,也保证不会有一个国家与自己之间有道路。
Seter好不容易建好了所有道路,他现在在位于P号的首都。Seter想知道P号国家到任意一个国家最少需要经过几条道路。当然,Seter保证P号国家能到任意一个国家。
注意:可能有重边
线段树优化
我们朴素想法是把图建出来跑最短路。
直接建图边数爆炸。
尝试数据结构优化连边。
可以建两颗线段树,分别称为A和B。
A和B中同一个节点B向A连边权为0。
A中儿子向父亲连边权为0。
B中父亲向儿子连边权为0。
对于一条边,可以分别在两颗线段树定位对应区间。
建一个新的辅助点,A中都向它连边权为1,它向B中连边权为1。
这样的话,原图联通性没有改变,而且新图上p在A上的叶子走到每个点在A上的叶子的最短路除以2就是原图最短路。
建完图跑Dij+heap
#include<cstdio>
#include<algorithm>
#include<queue>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=500000+10,maxtot=5*maxn+10,maxm=maxtot*7,inf=1000000000;
struct dong{
int x,y;
friend bool operator<(dong a,dong b){
return a.y>b.y||a.y==b.y&&a.x<b.x;
}
} zlt;
priority_queue<dong> dl;
int h[maxtot],go[maxm],dis[maxm],next[maxm],left[maxtot],right[maxtot],f[maxtot],leaf[maxn],sta[80];
bool bz[maxtot];
int i,j,k,l,r,t,n,m,p,now,tot,top,root1,root2;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(int x,int y,int z){
go[++top]=y;
dis[top]=z;
next[top]=h[x];
h[x]=top;
}
void build(int &x,int l,int r,int p){
x=++tot;
if (l==r){
if (p==1) leaf[l]=x;
return;
}
int mid=(l+r)/2;
build(left[x],l,mid,p);build(right[x],mid+1,r,p);
if (p==1){
add(left[x],x,0);
add(right[x],x,0);
}
else{
add(x,left[x],0);
add(x,right[x],0);
}
}
void connect(int x,int y,int l,int r){
add(y,x,0);
if (l==r) return;
int mid=(l+r)/2;
connect(left[x],left[y],l,mid);
connect(right[x],right[y],mid+1,r);
}
void link(int x,int l,int r,int a,int b,int p){
if (l==a&&r==b){
if (p==1) add(x,tot,1);else add(tot,x,1);
return;
}
int mid=(l+r)/2;
if (b<=mid) link(left[x],l,mid,a,b,p);
else if (a>mid) link(right[x],mid+1,r,a,b,p);
else{
link(left[x],l,mid,a,mid,p);
link(right[x],mid+1,r,mid+1,b,p);
}
}
void write(int x){
if (!x){
putchar('0');
putchar('\n');
return;
}
top=0;
while (x){
sta[++top]=x%10;
x/=10;
}
while (top) putchar('0'+sta[top--]);
putchar('\n');
}
int main(){
//freopen("data.in","r",stdin);
n=read();m=read();p=read();
build(root1,1,n,1);build(root2,1,n,-1);
connect(root1,root2,1,n);
fo(i,1,m){
j=read();k=read();l=read();r=read();
++tot;
link(root1,1,n,j,k,1);link(root2,1,n,l,r,-1);
swap(j,l);swap(k,r);
++tot;
link(root1,1,n,j,k,1);link(root2,1,n,l,r,-1);
}
t=leaf[p];
f[t]=0;
zlt.x=t;zlt.y=0;
dl.push(zlt);
fo(i,1,tot)
if (i!=t){
zlt.x=i;zlt.y=f[i]=inf;
dl.push(zlt);
}
fo(i,1,tot-1){
do{
zlt=dl.top();
dl.pop();
now=zlt.x;
}while (bz[now]);
bz[now]=1;
t=h[now];
while (t){
if (f[now]+dis[t]<f[go[t]]){
f[go[t]]=f[now]+dis[t];
zlt.x=go[t];zlt.y=f[go[t]];
dl.push(zlt);
}
t=next[t];
}
}
fo(i,1,n) write(f[leaf[i]]/2);
}