Problem
三种方案:v to u,v to [l,r],[l,r] to v。 求单源最短路。
Solution
由于存在结点与区间内所有结点间的连边,可以考虑用线段树优化建图。 具体来说维护两个线段树,线段树1表示有向边的终止结点,同时父亲连向儿子权为0;线段树2表示有向边的起始结点,同时儿子连向父亲权为0。两线段树的叶子结点间连无向边权为0(线段树1的叶子结点连向线段树2的叶子结点也可),表示同一结点自己和自己是连通的;对于任意有向边,线段树2连向线段树1,如图:
Code
# include <iostream>
# include <cstdio>
# include <cstring>
# include <queue>
using namespace std;
const int maxn = 1e6 + 5 , D = 5e5 ;
int n, m, cnt, last[ maxn] , num[ 100005 ] , s;
long long d[ maxn] ;
struct edge {
int v, w, next;
} e[ 4000005 ] ;
inline void add ( int u, int v, int w)
{
e[ ++ cnt] . v = v;
e[ cnt] . w = w;
e[ cnt] . next = last[ u] ;
last[ u] = cnt;
}
struct heapnode {
int u;
long long d;
bool operator < ( const heapnode & a) const { return d> a. d; }
} ;
void build ( int x, int l, int r)
{
if ( l== r)
{
num[ l] = x;
add ( x, x+ D, 0 ) ;
return ;
}
int mid = ( l+ r) >> 1 ;
add ( x, x<< 1 , 0 ) ;
add ( x, x<< 1 | 1 , 0 ) ;
add ( ( x<< 1 ) + D, x+ D, 0 ) ;
add ( ( x<< 1 | 1 ) + D, x+ D, 0 ) ;
build ( x<< 1 , l, mid) ;
build ( x<< 1 | 1 , mid+ 1 , r) ;
}
void connect ( int x, int l, int r, int kl, int kr, int w, int tp, int v)
{
if ( l> kr|| r< kl) return ;
if ( l>= kl&& r<= kr)
{
if ( tp)
add ( x+ D, v, w) ;
else
add ( v, x, w) ;
return ;
}
int mid = ( l+ r) >> 1 ;
connect ( x<< 1 , l, mid, kl, kr, w, tp, v) ;
connect ( x<< 1 | 1 , mid+ 1 , r, kl, kr, w, tp, v) ;
}
void dijkstra ( )
{
memset ( d, - 1 , sizeof ( d) ) ;
d[ num[ s] ] = 0 ;
priority_queue< heapnode> q;
q. push ( { num[ s] , 0 } ) ;
while ( ! q. empty ( ) )
{
heapnode nd = q. top ( ) ;
q. pop ( ) ;
int u = nd. u;
if ( d[ u] != nd. d) continue ;
for ( int i= last[ u] ; i; i= e[ i] . next)
{
int v = e[ i] . v, w = e[ i] . w;
if ( d[ v] > d[ u] + w|| d[ v] == - 1 )
{
d[ v] = d[ u] + w;
q. push ( { v, d[ v] } ) ;
}
}
}
}
int main ( )
{
scanf ( "%d%d%d" , & n, & m, & s) ;
build ( 1 , 1 , n) ;
for ( int i= 1 , op, v, l, r, w, u; i<= m; ++ i)
{
scanf ( "%d" , & op) ;
if ( op!= 1 )
{
scanf ( "%d%d%d%d" , & v, & l, & r, & w) ;
connect ( 1 , 1 , n, l, r, w, op% 2 , num[ v] + ( op% 2 == 0 ? D: 0 ) ) ;
}
else {
scanf ( "%d%d%d" , & v, & u, & w) ;
connect ( 1 , 1 , n, v, v, w, op% 2 , num[ u] + ( op% 2 == 0 ? D: 0 ) ) ;
}
}
dijkstra ( ) ;
for ( int i= 1 ; i<= n; i++ )
cout<< d[ num[ i] ] << ' ' ;
return 0 ;
}