题意:给了若干条道路,道路是双向边,航线是单向边,给了一些政策,如果从a到b有一条航线,那么一定不能通过一些道路和一些航线,从b到a。
分析:因为有负边权存在,所以这道题应该用spfa,但是会卡掉传统的queue,可以加一个deque优化,对于每次加边,判断是加到队头还是队尾,如果当前被更新过的边小于还未出队的队头的边就加到队头,否则加到队尾。
还需要注意的是,那些政策的原因原本一些可以走的路,不能再走了。
#include<bits/stdc++.h>
using namespace std;
const int N = 25000,M = 5e5+10;
int e[M],w[M],ne[M],h[M],idx;
int e1[M],ne1[M],h1[M],idx1;
bool st[M];
int d[M];
int n,r,p,s;
//判断a,b之间的道路是否被政策影响
bool isValid(int a,int b)
{
for(int i = h1[a]; i != -1; i = ne1[i])
{
if(e1[i] == b)
return false;
}
return true;
}
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
//构建无效信息邻接表
void add1(int a,int b)
{
e1[idx1] = b, ne1[idx1] = h1[a], h1[a] = idx1 ++;
}
void spfa()
{
memset(d,0x3f,sizeof d);
deque<int> q;
// cout<<s<<endl;
q.push_back(s);
d[s]=0;
st[s]=true;
while(q.size())
{
int t=q.front();
// cout<<" "<<t<<endl;
q.pop_front();
st[t]=false;
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(isValid(t,j) &&d[j]>d[t]+w[i])
{
d[j]=d[t]+w[i];
if(!st[j])
{
if(d[j]<d[q.front()]) q.push_front(j);
else q.push_back(j);
st[j]=true;
}
}
}
}
}
int main()
{
memset(h,-1,sizeof h);
memset(h1,-1,sizeof h);
cin>>n>>r>>p>>s;
int a,b,c;
while(r--)
{
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
while(p--)
{
cin>>a>>b>>c;
add(a,b,c);
add1(b,a);
}
spfa();
for(int i=1;i<=n;i++)
{
if(d[i]==0x3f3f3f3f) cout<<"NO PATH"<<endl;
else cout<<d[i]<<endl;
}
return 0;
}