codeforces567E President and Roads

题目链接

题目大意:总统要回家,会经过一些街道,每条街道都是单向的并且拥有权值。现在,为了让总统更好的回家,要对每一条街道进行操作: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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值