1. 程式人生 > >【bzoj 3073】Journeys(線段樹優化建圖)

【bzoj 3073】Journeys(線段樹優化建圖)

傳送門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; }