题目
(n)个点的有向图,除了普通有向边((x,y,w)),
还有点(x)向区间([l,r])或区间([l',r'])向点(x')连边,
问从点1到所有点的距离
分析
考虑最短路径,但是直接建边边数在(O(nm))级别内,
考虑建两棵线段树,一棵下行边权为0,一棵上行边权为0,
对于((x,y,w))直接连边即可,
对于点(x)连向([l,r]),将区间拆成(O(logn))个线段树节点,
并将点(x)连向下行的([l,r])线段树中,
同理,上行的([l',r'])连向点(x')中,这样边数为(O(mlogn)),
加上Dijkstra的时间复杂度为(O(mlog^2n))
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=300011; typedef long long lll;
struct node{int y,w,next;}e[N<<3]; pair<lll,int>heap[N];
int Cnt,n,m,S,as[N],et=1,cnt,ls[N],rs[N],root; lll dis[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void add(int x,int y,int w){e[++et]=(node){y,w,as[x]},as[x]=et;}
inline void Push(pair<lll,int>w){
heap[++Cnt]=w;
rr int x=Cnt;
while (x>1){
if (heap[x]<heap[x>>1])
swap(heap[x],heap[x>>1]),x>>=1;
else return;
}
}
inline void Pop(){
heap[1]=heap[Cnt--];
rr int x=1;
while ((x<<1)<=Cnt){
rr int y=x<<1;
if (y<Cnt&&heap[y+1]<heap[y]) ++y;
if (heap[x]>heap[y]) swap(heap[x],heap[y]),x=y;
else return;
}
}
inline void Dijkstra(int S){
heap[++Cnt]=make_pair(0,S);
for (rr int i=1;i<=cnt;++i) dis[i]=1e15; dis[S]=0;
while (Cnt){
rr lll t=heap[1].first; rr int x=heap[1].second;
Pop(); if (t!=dis[x]) continue;
for (rr int i=as[x];i;i=e[i].next)
if (dis[e[i].y]>dis[x]+e[i].w){
dis[e[i].y]=dis[x]+e[i].w;
Push(make_pair(dis[e[i].y],e[i].y));
}
}
}
inline void build(int &k,int l,int r){
if (l==r) {k=l; return;}
if (!k) k=++cnt,++cnt;
rr int mid=(l+r)>>1;
build(ls[k],l,mid);
build(rs[k],mid+1,r);
add(k,ls[k],0),add(k,rs[k],0);
if (l==mid) add(ls[k],k^1,0);
else add(ls[k]^1,k^1,0);
if (mid+1==r) add(rs[k],k^1,0);
else add(rs[k]^1,k^1,0);
}
inline void update(int k,int l,int r,int x,int y,int z,int w){
if (l==r){
if (w<0) add(l,z,-w);
else add(z,l,w);
return;
}
if (l==x&&r==y){
if (w<0) add(k^1,z,-w);
else add(z,k,w);
return;
}
rr int mid=(l+r)>>1;
if (y<=mid) update(ls[k],l,mid,x,y,z,w);
else if (x>mid) update(rs[k],mid+1,r,x,y,z,w);
else update(ls[k],l,mid,x,mid,z,w),update(rs[k],mid+1,r,mid+1,y,z,w);
}
signed main(){
n=iut(),m=iut(),S=iut(),cnt=n;
if (!(cnt&1)) ++cnt;
build(root,1,n);
for (rr int i=1;i<=m;++i)
switch (iut()){
case 1:{
rr int x=iut(),y=iut(),w=iut();
add(x,y,w);
break;
}
case 2:{
rr int x=iut(),l=iut(),r=iut(),w=iut();
if (l==r) add(x,l,w);
else update(root,1,n,l,r,x,w);
break;
}
case 3:{
rr int x=iut(),l=iut(),r=iut(),w=iut();
if (l==r) add(l,x,w);
else update(root,1,n,l,r,x,-w);
break;
}
}
Dijkstra(S);
for (rr int i=1;i<=n;++i){
if (dis[i]==1e15) putchar('-'),putchar(49);
else print(dis[i]);
putchar(i==n?10:32);
}
return 0;
}