P5344

思路

把图建出来跑 dij 即可。

对于建图,可以想到对每个操作 建一个虚点,从 向虚点连代价为 的边,从虚点向 连代价为 的边。此时图中有 条边,无法接受,考虑优化建图。

按照线段树优化建图的思路,可以想到先树剖建线段树, 表示从上往下, 表示从下往上。把每条边变为多条链在线段树上分别建边。每条边有 条链,每条链建 条边,最短路 ,总复杂度

可以发现,通过树剖把树结构变为数组再优化并非最好,因为放弃了树形结构多了两个 。可以树上倍增优化。

对于每个点 个虚点,记为 ,表示从 到往上 级祖先的链, 同理线段树优化建图,表示从上往下或从下往上。

和 st 表的查询一样, 的祖先 的路径可以表示为 的第 个虚点和使 级祖先为 的某个 的祖先的第 个虚点。把 的路径向虚点连边,等同于把 到 lca 和 到 lca 分别向虚点连边。

每个点 个虚点,倍增时每个虚点向上一级连 条边。每个操作有 个虚点,分为 部分,每部分向虚点连 条边。这样一共有 个点和 条边。总复杂度

code

int n,m,s,num;
int f[maxn];
int fd(int x){
	if(x==f[x])return x;
	return f[x]=fd(f[x]);
}
struct ask{
	int u,v,uu,vv,w;
}a[maxm];
int cnt;
int head[maxm*3],tot;
struct nd{
	int nxt,to,w;
}e[maxm*12];
void add(int u,int v,int w){
	e[++tot]={head[u],v,w};
	head[u]=tot;
}
int dep[maxn],to[maxn][20];
int in[maxn][20],out[maxn][20];
void dfs(int u,int fa){
	to[u][0]=fa;in[u][0]=out[u][0]=u;
	for(int i=1;(1<<i)<dep[u];i++){
		to[u][i]=to[to[u][i-1]][i-1];
	}
	for(int i=1;(1<<i)<=dep[u];i++){
		in[u][i]=++num;out[u][i]=++num;
		add(out[u][i-1],out[u][i],0);
		add(in[u][i],in[u][i-1],0);
		add(out[to[u][i-1]][i-1],out[u][i],0);
		add(in[u][i],in[to[u][i-1]][i-1],0);
	}
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v!=fa&&v<=n){
			dep[v]=dep[u]+1;
			dfs(v,u);
		}
	}
}
int lg[maxn];
int lca(int u,int v){
	if(u==v)return u;
	if(dep[u]<dep[v])swap(u,v);
	for(int i=lg[dep[u]];i>=0;i--)if(dep[to[u][i]]>=dep[v])u=to[u][i];
	if(u==v)return u;
	for(int i=lg[dep[u]];i>=0;i--)if(to[u][i]!=to[v][i])u=to[u][i],v=to[v][i];
	return to[u][0];
}
int kfa(int u,int k){
	int j=0;
	while(k){
		if(k&1)u=to[u][j];    
		k>>=1;
		++j;
	}
	return u;
}
void build(int u,int v,int w,int t){
	int k=lg[dep[u]-dep[v]+1];
	if(!t)add(out[u][k],num,w);
	else add(num,in[u][k],w);
	u=kfa(u,dep[u]-dep[v]+1-(1<<k));
	if(!t)add(out[u][k],num,w);
	else add(num,in[u][k],w);
}
int dis[maxm*3];
bool vis[maxm*3];
struct Dis{
	int dis,id;
	bool operator <(const Dis&tmp)const{return dis>tmp.dis;}
};
priority_queue<Dis> q;
 
int T;
signed main(){
	//	freopen(".in","r",stdin);
	//	freopen(".out","w",stdout);
	
	n=read();m=read();s=read();
	lg[1]=0;for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n;i++)f[i]=i;
	while(m--){
		int opt,u,v,w,uu,vv;opt=read();
		if(opt==1){
			u=read();v=read();uu=read();vv=read();w=read();
			if(fd(u)!=fd(v)||fd(uu)!=fd(vv))continue;
			a[++cnt]={u,v,uu,vv,w};
		}
		else{
			u=read();v=read();w=read();
			if(fd(u)==fd(v))continue;
			add(u,v,w);add(v,u,w);
			f[fd(u)]=fd(v);
		}
	}
	num=n;
	for(int i=1;i<=n;i++){
		if(!dep[i]){
			dep[i]=1;
			dfs(i,0);
		}
	}
	for(int i=1;i<=cnt;i++){
		num++;
		int tp1=lca(a[i].u,a[i].v),tp2=lca(a[i].uu,a[i].vv);
		build(a[i].u,tp1,0,0);build(a[i].v,tp1,0,0);
		build(a[i].uu,tp2,a[i].w,1);build(a[i].vv,tp2,a[i].w,1);
	}
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;q.push({0,s});
	while(!q.empty()){
		int u=q.top().id;q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				q.push({dis[v],v});
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(dis[i]>=0x3f3f3f3f)printf("-1 ");
		else printf("%d ",dis[i]);
	}
}