给定n个点,有三种操作:
1.连一条从x到y权值为w的边。
2.连一条从[l,r]到y权值为w的边。
3.连一条y到[l,r]权值为w的边。
给定一个起点,求单源最短路。
/*
线段树优化建图
对于点到区间上所有点都加上一条路径这样的操作
可以考虑线段树来优化建图
将区间考虑成点,那么点到区间的边就变成为点到一些点的边(这些点不会超过log次)
线段树的叶子节点就是真实的点
线段树每个节点又需要拆为两个点,一个点可以到达它的所有儿子,一个点可以被它的所有儿子到达
从这个区间出去一条路径(这个是从其儿子节点跑出去的),从一个点进入这个区间(节点进去这个区间跑到儿子节点去)
*/
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
struct node{ //线段树节点
int l,r;
int id1,id2;
}a[maxn*4];
int cnt = 0; //每个线段树节点对应了两个点的编号
struct nodex{
int id;
ll val;
nodex(int a,ll b)
{
id = a;
val = b;
}
bool operator<(const nodex&n)const
{
return val > n.val;
}
};
int p[maxn]; //i这个点被映射成了哪个点
vector<nodex> g[8*maxn]; //记得开8倍
ll dist[maxn*8],vis[maxn*8];
void update(int x) //线段树对应到图上的结构
{
a[x].id1 = ++cnt;
g[a[x].id1].push_back(nodex(a[2*x].id1,0)); //id1可以到达任意的儿子节点
g[a[x].id1].push_back(nodex(a[2*x+1].id1,0));
a[x].id2 = ++cnt;
g[a[2*x].id2].push_back(nodex(a[x].id2,0)); //id2被任意儿子节点到达
g[a[2*x+1].id2].push_back(nodex(a[x].id2,0));
}
void build(int x,int l,int r) //建树
{
a[x].l = l,a[x].r = r;
if( l == r )
{
a[x].id1 = ++cnt;
a[x].id2 = a[x].id1;
p[l] = cnt;
return;
}
int m = (l+r)>>1;
build(2*x,l,m);build(2*x+1,m+1,r);
update(x);
}
void add(int x,int l,int r,int p,ll w,int dir) //dir表示从p到[l,r]还是[l,r]到p
{
if( a[x].l == l && a[x].r == r )
{
if( dir == 0 ) g[a[x].id2].push_back(nodex(p,w)); //dir==0表示从[l,r]连向p,这里需要用id2
else g[p].push_back(nodex(a[x].id1,w)); //否则用id1
return;
}
int m = (a[x].l+a[x].r)>>1;
if( r <= m ) add(2*x,l,r,p,w,dir);
else if( l > m ) add(2*x+1,l,r,p,w,dir);
else
{
add(2*x,l,m,p,w,dir);
add(2*x+1,m+1,r,p,w,dir);
}
}
void dij(int begin)
{
for (int i = 1; i <= cnt; i++)
{
dist[i] = 1e18;
vis[i] = 0;
}
priority_queue<nodex> q;
dist[begin] = 0;
q.push(nodex(begin,0));
while( !q.empty() )
{
int x = q.top().id;
q.pop();
if( vis[x] ) continue;
vis[x] = 1;
for (int i = 0; i < g[x].size(); i++)
{
int t = g[x][i].id;
if( dist[t] > dist[x] + g[x][i].val )
{
dist[t] = dist[x] + g[x][i].val;
q.push(nodex(t,dist[t]));
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n,q,s;
cin >> n >> q >> s;
build(1,1,n);
while( q-- )
{
int op;
cin >> op;
if( op == 1 )
{
int x,y,v;
cin >> x >> y >> v;
add(1,x,x,p[y],v,0);
}else
{
int v,l,r,w;
cin >> v >> l >> r >> w;
if( op == 2 ) add(1,l,r,p[v],w,1);
else add(1,l,r,p[v],w,0);
}
}
dij(p[s]);
for (int i = 1; i <= n; i++)
{
if( dist[p[i]] == 1e18 ) cout << -1;
else cout << dist[p[i]];
if( i == n ) cout << '\n';
else cout << ' ';
}
return 0;
}