Codeforces Round #Pi (Div. 2) E. President and Roads (最短路+强连通求割边)

题目地址:codeforces #pi (DIV2) E
题目很水。。就是先求两边最短路,然后把可能为最短路的边挑出来,然后判断是否yes只需要转化成无向图跑一遍tarjan,找出割边,割边就是yes,然后剩下的边就让它的值为最短路-1就行了,如果-1后变成了非正数,就是no.
但是!!!居然卡spfa!!那是不是说cf以后就不能用可以卡的算法了。。完全可以出组数据来卡这些算法。。。比如spfa,isap。。。
于是为了这题,又看了一遍迪杰斯特拉算法。。
代码如下:

#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
#include <algorithm>
using namespace std ;
#pragma comment(linker, "/STACK:102400000,102400000")
#define LL __int64
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int MAXN=100000+10;
int head[MAXN], cnt, source, sink, vis[MAXN], ok[MAXN];
LL d[2][MAXN];
struct N
{
        int u, v;
        LL w;
}fei[MAXN];
struct node
{
        int u, v, next;
        LL w;
}edge[MAXN];
void add(int u, int v, LL w)
{
        edge[cnt].v=v;
        edge[cnt].w=w;
        edge[cnt].next=head[u];
        head[u]=cnt++;
}
void init(int n, int x)
{
        memset(head,-1,sizeof(head));
        cnt=0;
        for(int i=1;i<=n;i++){
                d[x][i]=(LL)1e15;
        }
}
struct Heap
{
        LL w;
        int id;
        Heap () {}
        Heap(LL w, int id): w(w),id(id) {}
        bool operator < (const Heap &a) const{
                return w>a.w;
        }
};
priority_queue<Heap>q;
void dijk(int x, int st)
{
        memset(vis,0,sizeof(vis));
        while(!q.empty()) q.pop();
        q.push(Heap(0,st));
        d[x][st]=0;
        while(!q.empty()){
                int u=q.top().id;
                q.pop();
                if(vis[u]) continue ;
                vis[u]=1;
                for(int i=head[u];i!=-1;i=edge[i].next){
                        int v=edge[i].v;
                        if(d[x][v]>d[x][u]+edge[i].w){
                                d[x][v]=d[x][u]+edge[i].w;
                                q.push(Heap(d[x][v],v));
                        }
                }
        }
}
int dfn[MAXN], low[MAXN], indx;
vector<pair<int,int> >G[MAXN];
void init1(int n)
{
        memset(dfn,0,sizeof(dfn));
        indx=0;
        memset(ok,0,sizeof(ok));
        for(int i=1;i<=n;i++){
                G[i].clear();
        }
}
void tarjan(int u, int fa)
{
        dfn[u]=low[u]=++indx;
        int flag=0;
        for(int i=0;i<G[u].size();i++){
                int v=G[u][i].first;
                if(v==fa&&!flag){
                        flag=1;
                        continue ;
                }
                if(!dfn[v]){
                        tarjan(v,u);
                        low[u]=min(low[u],low[v]);
                        if(dfn[u]<low[v]){
                                ok[G[u][i].second]=1;
                        }
                }
                else low[u]=min(low[u],dfn[v]);
        }
}
int main()
{
        int n, m, i, u, v, j;
        LL w;
        while(scanf("%d%d%d%d",&n,&m,&source,&sink)!=EOF){
                init(n,0);
                for(i=0;i<m;i++){
                        scanf("%d%d%I64d",&fei[i].u,&fei[i].v,&fei[i].w);
                        add(fei[i].u,fei[i].v,fei[i].w);
                }
                dijk(0,source);
                init(n,1);
                for(i=0;i<m;i++){
                        add(fei[i].v,fei[i].u,fei[i].w);
                }
                dijk(1,sink);
                init1(n);
                for(i=0;i<m;i++){
                        u=fei[i].u;
                        v=fei[i].v;
                        if(d[0][u]+d[1][v]+fei[i].w==d[0][sink]){
                                G[u].push_back(make_pair(v,i));
                                G[v].push_back(make_pair(u,i));
                        }
                }
                tarjan(source,-1);
                for(i=0;i<m;i++){
                        if(ok[i]){
                                puts("YES");
                                continue ;
                        }
                        u=fei[i].u;v=fei[i].v;
                        w=d[0][sink]-d[0][u]-d[1][v];
                        w--;
                        if(w<=0) puts("NO");
                        else printf("CAN %I64d\n",fei[i].w-w);
                }
        }
        return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值