题目大意:总统要回家,会经过一些街道,每条街道都是单向的并且拥有权值。现在,为了让总统更好的回家,要对每一条街道进行操作:1)如果该街道一定在最短路上,则输出“YES”。2)如果该街道修理过后,该边所在的最短路可以取代原先的最短路,则输出“CAN x”,x是修改该街道的花费,就是权值减小的值。3)如果该街道是一条不连通的街道,或者修改过后权值小于等于0,则输出“NO”。
解析:需要迪杰斯特拉和tarjan的结合,不熟悉的话可以点开链接。
正向取边,求一次最短路得到d1[], 然后反向取边,再求一次最短路得到d2[]。接着开始判断每一条边是否在最短路上。把这些边构成一个新的图,然后利用tarjan判断每一条边是否是必不可少的。之后判断不是桥的每一条边是否可以被修改,也就是d1[t]-d1[a[i]]-d2[b[i]]-1>0
具体细节看代码
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=a;i<b;i++)
#define rep1(i,a,b) for(int i=a;i>=b;i--)
#define INF 1000000000000000000LL
using namespace std;
const int N=1e5+100;
long long a[N],b[N],l[N],d1[N],d2[N],dfn[N],low[N],n,m,s,t,index;
bool bridge[N],vis[N];
vector<pair<long long,long long> > edge[N];
void dijkstra(long long v,long long *d)
{
long long t;
priority_queue<pair<long long,long long>,vector<pair<long long,long long> >,greater<pair<long long,long long> > > pq;
for(long long i=1;i<=n;i++)
d[i]=INF;
d[v]=0;
pq.push(make_pair(0,v));
while(!pq.empty())
{
t=pq.top().second;
pq.pop();
for(long long i=0;i<edge[t].size();i++)
if(d[edge[t][i].first]>d[t]+edge[t][i].second)
{
d[edge[t][i].first]=d[t]+edge[t][i].second;
pq.push(make_pair(d[edge[t][i].first],edge[t][i].first));
}
}
return;
}
void tarjan(long long x)
{
index++;
dfn[x]=index;
low[x]=index;
for(long long i=0;i<edge[x].size();i++)
{
if(vis[edge[x][i].second])
continue;
vis[edge[x][i].second]=true;
if(!dfn[edge[x][i].first])
{
tarjan(edge[x][i].first);
low[x]=min(low[x],low[edge[x][i].first]);
if(dfn[x]<low[edge[x][i].first])
bridge[edge[x][i].second]=true;
}
else low[x]=min(low[x],dfn[edge[x][i].first]);
}
return;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>s>>t;
for(long long i=0;i<m;i++)
cin>>a[i]>>b[i]>>l[i];
for(long long i=0;i<m;i++)
edge[a[i]].push_back(make_pair(b[i],l[i]));
dijkstra(s,d1);//正向求最短路
for(long long i=1;i<=n;i++)
edge[i].clear();
for(long long i=0;i<m;i++)
edge[b[i]].push_back(make_pair(a[i],l[i]));
dijkstra(t,d2);//反向求最短路
for(long long i=1;i<=n;i++)
edge[i].clear();
for(long long i=0;i<m;i++)//制造一个新图
if(d1[a[i]]+l[i]+d2[b[i]]==d1[t])//如果该边在最短路上
{
edge[a[i]].push_back(make_pair(b[i],i));
edge[b[i]].push_back(make_pair(a[i],i));
}
tarjan(s);
for(long long i=0;i<m;i++)
{
if(bridge[i])
cout<<"YES"<<endl;
else if(d1[t]-d1[a[i]]-d2[b[i]]-1>0)//该边可以修改
cout<<"CAN "<<l[i]-(d1[t]-d1[a[i]]-d2[b[i]]-1)<<endl;
else cout<<"NO"<<endl;
}
return 0;
}