【bzoj 3073】Journeys(線段樹優化建圖)
阿新 • • 發佈:2019-02-01
傳送門biu~
線段樹的每個節點代表一個區間,建兩棵線段樹。
出線段樹每個點向父節點連邊0,表示如果能從這個區間出發也就可以從父區間出發。入線段樹每個點向子節點連邊0,表示如果能到達這個區間也就可以到達子區間。
入線段樹每個點向出線段樹的平行結點連邊0,表示如果能到達這個區間也可以從這個區間出發。
線上段樹上跑最短路,到葉子節點的路徑長即為最短路徑。
#include<bits/stdc++.h>
using namespace std;
int n,m,p,cnt;
int head[4000005],nex[30000005],to[30000005],v[30000005],tp;
int dis[4000005],pos[4000005 ];
bool in[4000005];
void spfa(int st){
memset(dis,127,sizeof(dis));
dis[st]=0;
queue<int>q;q.push(st);
while(!q.empty()){
int x=q.front();q.pop();in[x]=0;
for(int i=head[x];i;i=nex[i]){
if(dis[x]+v[i]<dis[to[i]]){
dis[to[i]]=dis[x]+v[i];
if (!in[to[i]]){
in[to[i]]=1;
q.push(to[i]);
}
}
}
}
}
inline void add(int x,int y,int z){
nex[++tp]=head[x];
head[x]=tp;
to[tp]=y;
v[tp]=z;
}
struct Node{
Node *ch[2];
int L,R,num;
Node(int l=0 ,int r=0){L=l;R=r;num=cnt;ch[0]=ch[1]=NULL;}
}*root;
void init(Node *&o,int l,int r){
++cnt;o=new Node(l,r);
if(l==r) {pos[l]=cnt;return;}
int mid=l+r>>1;
init(o->ch[0],l,mid); init(o->ch[1],mid+1,r);
}
void build(Node *&o){
add(o->num+cnt,o->num,0);
if(o->L==o->R) return;
for(int i=0;i<=1;++i){
add(o->ch[i]->num,o->num,0);
add(o->num+cnt,o->ch[i]->num+cnt,0);
build(o->ch[i]);
}
}
void Link(Node *&o,int l,int r,int ord,int opt){
if(o->L==l && o->R==r){
if(!opt) add(o->num,ord,1);
else add(ord,o->num+cnt,0);
return;
}
int mid=o->L+o->R>>1;
if(r<=mid) Link(o->ch[0],l,r,ord,opt);
else if(l>mid) Link(o->ch[1],l,r,ord,opt);
else Link(o->ch[0],l,mid,ord,opt),Link(o->ch[1],mid+1,r,ord,opt);
}
int main(){
scanf("%d%d%d",&n,&m,&p);
init(root,1,n);
build(root);
for(int i=1;i<=m;++i)
for(int j=0;j<=1;++j){
int x,y;
scanf("%d%d",&x,&y);
Link(root,x,y,i+2*cnt,j);
Link(root,x,y,i+2*cnt+m,j^1);
}
spfa(pos[p]);
for(int i=1;i<=n;++i) printf("%d\n",dis[pos[i]]);
return 0;
}