思路:本题第一次首先用了spfa算法,但是被卡了
改进:注意到这是一个两层的图,然后我们可以在层内使用dijkstra算法,层间顺便使用dijkstra更新一下距离,这是不违反dijkstra算法的证明的。
坑点:在进行层间dijkstra的时候,要记得特判可能加入进来的这个点是不是这个层的
如果不是这个层的,我们就将其所在的联通块的入度-1即可。
坑点2:要记得在开始的时候把所有入度为0的块都加入进去,理由是:为了保证拓扑的正常进行,如果有一个入度为0的块和别的块连接,那么这个块就可能根本进不去这个队列,所以我们要先把他们都入队
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N = 2e5 + 50;
int belong[N];//每个结点属于哪个联通块
vector<int>block[N];
queue<int>q;
vector<int>block_to[N];
int in[N];//记录每个联通块的入度
int d[N];
bool vis[N];
vector<pair<int, int>>to[N];//val dest
int t, r, p, s;
void add(int a, int b, int c)
{
to[a].push_back({ c,b });
}
void dfs(int u, int fa)
{
belong[u] = fa;
block[fa].push_back(u);
for (auto& i : to[u])
{
int j = i.second;
if (!belong[j])
{
dfs(j, fa);
}
}
}
void dijkstra(int s)//块的id
{
priority_queue<pii, vector<pii>, greater<pii>>h;
for (auto& i : block[s])
{
h.push({ d[i],i });
}
while (!h.empty())
{
auto t = h.top();
h.pop();
int v = t.second;
if (vis[v])
{
continue;
}
vis[v] = true;
for (auto& i : to[v])
{
int j = i.second;
int w = i.first;
if (d[v] + w < d[j])
{
d[j] = d[v] + w;
if (belong[j]==belong[v])
{
h.push({ d[j],j });
}
}
if (belong[j]!= belong[v])
{
in[belong[j]]--;
if (!in[belong[j]])
{
q.push(belong[j]);
}
}
}
}
/*for(auto&i:block_to[belong[s]])
{
in[i]--;
if (!in[i])
{
q.push(i);
}
}*/
}
void topoSort()
{
set<int>st;
for(int i=1;i<=t;i++)
{
if (!in[belong[i]])
{
st.insert(belong[i]);
}
}
for (auto& i : st)
{
q.push(i);
}
//q.push(belong[s]);
memset(d, 0x3f, sizeof d);
d[s] = 0;
while (!q.empty())
{
auto t = q.front();
q.pop();
dijkstra(t);
}
}
signed main()
{
cin >> t >> r >> p >> s;
for (int i = 0; i < r; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
for (int i = 1; i <= t; i++)
{
if (!belong[i])
{
dfs(i, i);
}
//cout << "i==" << i << " belong[i]==" << belong[i] << endl;
}
for (int i = 0; i < p; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
in[belong[b]]++;
// block_to[belong[a]].push_back(belong[b]);
}
topoSort();
//cout << "test\n\n";
for (int i = 1; i <= t; i++)
{
if (d[i] > 0x3f3f3f3f/2)
{
cout << "NO PATH" << endl;
}
else
{
cout << d[i] << endl;
}
}
return 0;
}