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;
}