看上去就是要到最短路,但是这题数据经过构造会卡SPFA(大家都嫌弃他嘤嘤,but可以用SLF优化水过),且因为有负权会卡Dijkstra。
那么我们观察题意,发现只有单向边是有负权的,双向边没有负权,且单向边不会构成环!那么我们就可以把原图看作许多个由双向边组成的连通块,连通块由单向边互相连在一起形成一个DAG图,对于DAG图 我们就可以用拓扑序在线性时间内遍历求出答案,对于连通块内的最短路信息因为双向边没有负权可以用Dijkstra直接处理。
那么实现的话首先就可以先把双向边连起来,用dfs求出连通块,在拓扑排序遍历连通块的大框架下对于每一个连通块内的跑Dij即可。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N=3e5+10,M=3e5+10;
const int INF=0x7f7f7f7f;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
struct edge
{
int x,y,c,next;
}a[N]; int len,last[N];
void ins(int x,int y,int c)
{
a[++len].x=x;a[len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
}
bool v[N];
int cnt;
vector<int> has[N];
int bl[N];
void dfs(int x)
{
v[x]=1;
has[cnt].push_back(x);
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(!v[y])bl[y]=bl[x],dfs(y);
}
}
struct node
{
int d,id;
bool operator <(const node &b) const
{
return d>b.d;
}
};
priority_queue<pair<int,int> > q;
int deg[N];
int n,R,P,st;
int list[M],head,tail;
int dis[N];
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
n=read(); R=read(); P=read(); st=read();
len=0; memset(last,0,sizeof(last));
for(int i=1;i<=R;i++)
{
int x=read(),y=read(),c=read();
ins(x,y,c);
ins(y,x,c);
}
//get scc
cnt=0; memset(bl,0,sizeof(bl));
memset(v,0,sizeof(v));
for(int i=1;i<=n;i++)
if(!v[i])
{
cnt++; bl[i]=cnt;
dfs(i);
}
//rebuild to DAG
memset(deg,0,sizeof(deg));
for(int i=1;i<=P;i++)
{
int x=read(),y=read(),c=read();
ins(x,y,c); ins(bl[x]+n,bl[y]+n,c);
}
//Get deg
head=1,tail=1;
list[1]=bl[st]+n;
memset(v,0,sizeof(v));
while(head<=tail)
{
int x=list[head];
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(!v[y])v[y]=1,list[++tail]=y;
deg[y-n]++;
}
head++;
}
//Dij+Topsort
memset(dis,0x7f,sizeof(dis)); dis[st]=0;
memset(v,0,sizeof(v));
head=1,tail=1;
list[1]=bl[st];
while(head<=tail)
{
int cc=list[head];
// for(int i=1;i<=n;i++)if(bl[i]==cc)q.push(make_pair(-dis[i],i));
int siz=has[cc].size();
for(int i=0;i<siz;i++) q.push(make_pair(-dis[has[cc][i]],has[cc][i]));
while(q.size())
{
int x=q.top().second;q.pop();
if(v[x])continue;
v[x]=1;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(bl[x]!=bl[y]){deg[bl[y]]--;
if(deg[bl[y]]==0)list[++tail]=bl[y];}
if(dis[y]>dis[x]+a[k].c)
{
dis[y]=dis[x]+a[k].c;
if(bl[x]==bl[y])q.push(make_pair(-dis[y],y));
}
}
}
head++;
}
for(int i=1;i<=n;i++)
{
if(dis[i]==INF) puts("NO PATH");
else printf("%d\n",dis[i]);
}
return 0;
}