const int MAXN=1e5+5;
const LL Inf=1e18;
struct Edge{
int to,w,next;
}edge[MAXN*30];
int head[MAXN<<3],edge_cnt;
void Insert(int u,int v,int w){
edge[++edge_cnt]=Edge{v,w,head[u]};
head[u]=edge_cnt;
}
template <typename T>
struct dijkstra{
T dis[MAXN<<3];
bool vis[MAXN<<3];
priority_queue<pair<T,int>,vector<pair<T,int> >,greater<pair<T,int> > >q;
void solve(int src,int n){
mem(vis,0);
_rep(i,1,n)
dis[i]=Inf;
dis[src]=0;
q.push(make_pair(dis[src],src));
while(!q.empty()){
pair<T,int> temp=q.top();q.pop();
int u=temp.second;
if(vis[u])
continue;
vis[u]=true;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(dis[v]>edge[i].w+dis[u]){
dis[v]=edge[i].w+dis[u];
q.push(make_pair(dis[v],v));
}
}
}
}
};
dijkstra<LL> solver;
int lef[MAXN<<2],rig[MAXN<<2],Tree1[MAXN<<2],Tree2[MAXN<<2],node_cnt;
void build(int k,int L,int R){
lef[k]=L,rig[k]=R;
int M=L+R>>1;
if(L==R){
Tree1[k]=Tree2[k]=M;
return;
}
Tree1[k]=++node_cnt,Tree2[k]=++node_cnt;
build(k<<1,L,M);
build(k<<1|1,M+1,R);
Insert(Tree1[k],Tree1[k<<1],0);Insert(Tree1[k],Tree1[k<<1|1],0);
Insert(Tree2[k<<1],Tree2[k],0);Insert(Tree2[k<<1|1],Tree2[k],0);
}
void AddEdge1(int k,int L,int R,int v,int w){
if(L<=lef[k]&&rig[k]<=R)
return Insert(v,Tree1[k],w);
int mid=lef[k]+rig[k]>>1;
if(mid>=L)
AddEdge1(k<<1,L,R,v,w);
if(mid<R)
AddEdge1(k<<1|1,L,R,v,w);
}
void AddEdge2(int k,int L,int R,int v,int w){
if(L<=lef[k]&&rig[k]<=R)
return Insert(Tree2[k],v,w);
int mid=lef[k]+rig[k]>>1;
if(mid>=L)
AddEdge2(k<<1,L,R,v,w);
if(mid<R)
AddEdge2(k<<1|1,L,R,v,w);
}
void Init(int n){
node_cnt=n;
build(1,1,n);
}
int main()
{
int n=read_int(),m=read_int(),s=read_int();
Init(n);
while(m--){
int type=read_int();
if(type==1){
int u=read_int(),v=read_int(),w=read_int();
Insert(u,v,w);
}
else{
int v=read_int(),l=read_int(),r=read_int(),w=read_int();
if(type==2)
AddEdge1(1,l,r,v,w);
else
AddEdge2(1,l,r,v,w);
}
}
solver.solve(s,node_cnt);
_rep(i,1,n)
space(solver.dis[i]==Inf?-1:solver.dis[i]);
return 0;
}