#include<bits/stdc++.h>
#define int long long
using namespace std;
const int D=600005;//足够远的距离区分两棵线段树
int n,m,root,op,x,y,l,r,k;
int ver[4000005],ne[4000005],head[4000005],w[4000005],tot;
void add(int x,int y,int z){
ver[++tot]=y,ne[tot]=head[x],w[tot]=z,head[x]=tot;
}
int df[1000005];//每个单点对应的线段树位置
void build(int root,int l,int r){
if(l==r){ df[l]=root;return; }
add(root,root<<1,0);
add(root,root<<1|1,0);
add((root<<1)+D,root+D,0);
add((root<<1|1)+D,root+D,0);
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
}
void update(int root,int l,int r,int fl,int fr,int k,int x,int op){
if(fl<=l&&r<=fr){
if(op==2) add(k,root,x);
else add(root+D,k,x);
return;
}
int mid=(l+r)>>1;
if(fl<=mid) update(root<<1,l,mid,fl,fr,k,x,op);
if(fr>mid) update(root<<1|1,mid+1,r,fl,fr,k,x,op);
}
struct node{
int k,x;
bool operator <(const node &b) const{
return x>b.x;
}
};
priority_queue<node> q;
bool flag[4000005];
int d[4000005];
void dij(int root){
for(int i=1;i<=4000005;++i) d[i]=1e18,flag[i]=0;
d[df[root]]=0,q.push({df[root],0});
while(!q.empty()){
int x=q.top().k;
q.pop();
if(flag[x]) continue;
flag[x]=1;
for(int i=head[x];~i;i=ne[i]){
if(d[ver[i]]>d[x]+w[i])
d[ver[i]]=d[x]+w[i],q.push({ver[i],d[ver[i]]});
}
}
}
signed main(){
scanf("%lld %lld %lld",&n,&m,&root);
build(1,1,n);
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++){
scanf("%lld",&op);
if(op==1){
scanf("%lld %lld %lld",&x,&y,&k);
add(df[x],df[y],k);
}
else{
scanf("%lld %lld %lld %lld",&x,&l,&r,&k);
update(1,1,n,l,r,df[x],k,op);
}
}
for(int i=1;i<=n;i++) add(df[i],df[i]+D,0);
dij(root);
for(int i=1;i<=n;i++){
if(d[df[i]]==1e18) cout<<-1<<" ";
else cout<<d[df[i]]<<" ";
}
return 0;
}
谢谢。