bzoj 3073 Journeys —— 线段树优化连边
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3073
建两棵线段树,一棵从下往上连边,一棵从上往下连边,叶子节点之间也有连边;
区间向区间连边时,可以新建一个节点,log2n 条边就能变成 2logn 条边;
注意区间向区间连边也要连反边,别忘了连反边时 ++cnt !
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define mid ((l+r)>>1) using namespace std; int const xxn=5e5+5,xn=4e6+5,xm=3e7+5; int n,m,hd[xn],ct,to[xm],nxt[xm],w[xm],dis[xn]; int rt[2],cnt,ls[xxn<<2],rs[xxn<<2],st[xxn],ed[xxn]; bool vis[xn]; struct N{ int d,id; bool operator < (const N &y) const {return d==y.d?id<y.id:d>y.d;} }; priority_queue<N>q; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } int gt[20]; void wr(int x) { if(!x){puts("0"); return;} if(x<0)putchar('-'),x=-x; int t=0; while(x)gt[++t]=x%10,x/=10; for(int i=t;i;i--)putchar(gt[i]+'0'); puts(""); } void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;} void build(int x,int l,int r,bool tp) { if(l==r) { if(!tp)st[l]=x; else ed[l]=x; return; } ls[x]=++cnt; rs[x]=++cnt; build(ls[x],l,mid,tp); build(rs[x],mid+1,r,tp); if(!tp)add(ls[x],x,0),add(rs[x],x,0); else add(x,ls[x],0),add(x,rs[x],0); } void link(int x,int l,int r,int L,int R,int c,bool tp) { if(l>=L&&r<=R) { if(!tp)add(x,c,1); else add(c,x,0); return; } if(mid>=L)link(ls[x],l,mid,L,R,c,tp); if(mid<R)link(rs[x],mid+1,r,L,R,c,tp); } void dij(int s) { memset(dis,0x3f,sizeof dis); dis[s]=0; q.push((N){0,s}); while(q.size()) { int x=q.top().id; q.pop(); if(vis[x])continue; vis[x]=1; for(int i=hd[x],u;i;i=nxt[i]) if(dis[u=to[i]]>dis[x]+w[i]) dis[u]=dis[x]+w[i],q.push((N){dis[u],u}); } } int main() { n=rd(); m=rd(); int p=rd(); rt[0]=++cnt; build(rt[0],1,n,0); rt[1]=++cnt; build(rt[1],1,n,1); for(int i=1;i<=n;i++)add(ed[i],st[i],0); for(int i=1,a,b,c,d;i<=m;i++) { a=rd(); b=rd(); c=rd(); d=rd(); int t=++cnt; link(rt[0],1,n,a,b,t,0); link(rt[1],1,n,c,d,t,1); t=++cnt;//!!! link(rt[0],1,n,c,d,t,0); link(rt[1],1,n,a,b,t,1); } dij(ed[p]); for(int i=1;i<=n;i++)wr(dis[ed[i]]); return 0; }