题解:设有一条边x->y,数组dis1[i]表示从1到i的最短距离,dis2[i]表示从n到i的最短距离。
1 如果说将x->y反向之前没有经过x->y,但是反向后我经过了x,y说明找到了一个更优的路径,那么反向后的答案就是dis1[y]+dis2[x]+(x,y),如果说反向后我没有经过
x->y,那也就是说x->y正向反向对dis[n]的结果没有影响喽。
2 如果说反向之前我经过了x->y,如果反向后没有经过x->y,那么此时的最短路也一定是大于等于dis1[n]的,因为会有一条新的路径长度处于dis1[n]和dis1[y]+dis2[x]+(x,y)之间。如果反向后经过了x->y,那么反向后的答案就是dis1[y]+dis2[x]+(x,y)。
综上所述,我们只需要判断dis1[y]+dis2[x]+(x,y)和dis1[n]的关系就行了。(看起来有点绕,仔细品品还是很有意思的)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=2e5+7; const ll INF=1e18+7; struct stu{ ll a,b; bool friend operator<(const stu &x,const stu &y){ return x.b>y.b; } }; vector<stu>ve1[N]; vector<stu>ve2[N]; ll l[N],r[N],w[N]; ll n,m; bool mark[N]; ll dis1[N],dis2[N]; void add1(ll x,ll y,ll weight){ ve1[x].push_back({y,weight}); } void add2(ll x,ll y,ll weight){ ve2[x].push_back({y,weight}); } void inll(){ for(ll i=1;i<=n;i++){ dis1[i]=dis2[i]=INF; } } void djstrea1(ll s){ priority_queue<stu>que; dis1[s]=0; que.push({s,0}); while(que.size()){ stu xx=que.top(); que.pop(); if(mark[xx.a]==1) continue ; mark[xx.a]=1; for(ll i=0;i<ve1[xx.a].size();i++){ ll dx=ve1[xx.a][i].a; ll dy=ve1[xx.a][i].b; if(mark[dx]==0&&dis1[dx]>dis1[xx.a]+dy){ dis1[dx]=dis1[xx.a]+dy; que.push({dx,dis1[dx]}); } } } } void djstrea2(ll s){ priority_queue<stu>que; dis2[s]=0; que.push({s,0}); while(que.size()){ stu xx=que.top(); que.pop(); if(mark[xx.a]==1) continue ; mark[xx.a]=1; for(ll i=0;i<ve2[xx.a].size();i++){ ll dx=ve2[xx.a][i].a; ll dy=ve2[xx.a][i].b; if(mark[dx]==0&&dis2[dx]>dis2[xx.a]+dy){ dis2[dx]=dis2[xx.a]+dy; que.push({dx,dis2[dx]}); } } } } int main(){ cin>>n>>m; inll(); for(ll i=1;i<=m;i++){ ll x,y,z; cin>>x>>y>>z; l[i]=x;r[i]=y;w[i]=z; add1(x,y,z); add2(y,x,z); } djstrea1(1); memset(mark,0,sizeof mark); djstrea2(n); ll t; cin>>t; while(t--){ ll i;cin>>i; cout<<(dis1[n]>dis1[r[i]]+dis2[l[i]]+w[i]? "YES":"NO")<<endl; } return 0; }
原文地址:https://www.cnblogs.com/Accepting/p/12678654.html
时间: 2024-10-16 13:31:19