codeforces567E. President and Roads
传送门:http://codeforces.com/problemset/problem/567/E
思路:正着做一遍最短路,反着做一遍最短路,然后就可以判断一条边是否在最短路径图上了
设这条边为从a到b权值为c,那么如果dis[st][a]+c+dis[b][ed]=mindis,则在最短路径图上。
如果一条边是最短路图的桥,那么这就是必经边,
对于非必经边,就看减到多少才会使dis[st][a]+c+dis[b][ed]<mindis,
如果小于0,输NO,否则这条路就可修。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define PI pair<ll,ll> #define mp(a,b) make_pair(a,b) #define fi first #define se second const int maxn=200010,maxm=400010,maxq=maxn*5; using namespace std; typedef long long ll; ll n,m,st,ed,pre[3][maxm],now[3][maxn],son[3][maxm],val[3][maxm],frm[3][maxm],tot[3]; ll q[maxq+10],head,tail,top;ll dis[3][maxn],mindis,ans[maxm]; bool bo[maxn],must[maxn],ins[maxn],in[maxm],use[maxm];//must 一定在最短路上,in在最短路图上 ll tim,dfn[maxn],low[maxn],bcnt,bel[maxn]; void add(ll a,ll b,ll c,ll id){ pre[id][++tot[id]]=now[id][a]; now[id][a]=tot[id]; frm[id][tot[id]]=a; son[id][tot[id]]=b; val[id][tot[id]]=c; } bool operator >(PI a,PI b){ if (a.fi!=b.fi) return a.fi<b.fi; return a.se<b.se; } /*void spfa(ll c){ memset(dis[c],63,sizeof(dis[c])); memset(bo,0,sizeof(bo)); if (!c) q[tail=1]=st,bo[st]=1,dis[c][st]=0; else q[tail=1]=ed,bo[ed]=1,dis[c][ed]=0; head=0; while (head!=tail){ if (++head>maxq) head=1; ll x=q[head]; for (ll y=now[c][x];y;y=pre[c][y]){ ll xx=son[c][y]; if (dis[c][xx]>dis[c][x]+val[c][y]){ dis[c][xx]=dis[c][x]+val[c][y]; if (!bo[xx]){ if (++tail>maxq) tail=1; q[tail]=xx,bo[xx]=1; } } } bo[x]=0; } if (!c) mindis=dis[c][ed]; //printf("%d\n",mindis); }*/ bool cmp(PI a,PI b){return a>b;} void dijkstra(ll c){ memset(dis[c],63,sizeof(dis[c])); //memset(bo,0,sizeof(bo)); priority_queue< PI,vector<PI>,greater<PI> > q; if (!c) q.push(mp(0,st)),dis[c][st]=0; else q.push(mp(0,ed)),dis[c][ed]=0; while (!q.empty()){ ll x=q.top().se,d=q.top().fi; q.pop(); for (ll y=now[c][x];y;y=pre[c][y]){ ll xx=son[c][y]; if (dis[c][xx]>d+val[c][y]){ dis[c][xx]=d+val[c][y]; q.push(mp(dis[c][xx],xx)); } } } if (!c) mindis=dis[c][ed]; //printf("%d\n",mindis); } void rebuild(){ for (ll i=1;i<=m;i++){ ll a=frm[0][i],b=son[0][i],c=val[0][i]; if (dis[0][a]+dis[1][b]+c==mindis) in[i]=1,add(a,b,c,2),add(b,a,c,2); } } void tarjan(ll x,ll fa){ dfn[x]=low[x]=++tim,q[++top]=x,ins[x]=1; for (ll y=now[2][x];y;y=pre[2][y]){ if (use[y]) continue; ll xx=son[2][y]; use[y]=use[y^1]=1; if (!dfn[xx]) tarjan(xx,x),low[x]=min(low[x],low[xx]); else if (ins[xx]) low[x]=min(low[x],dfn[xx]); } if (low[x]==dfn[x]){ ll xx;bcnt++; do{ xx=q[top--],bel[xx]=bcnt,ins[xx]=0; }while (xx!=x); } } void work(){ for (ll i=1;i<=m;i++){ if (!in[i]) continue; ll a=frm[0][i],b=son[0][i]; if (bel[a]!=bel[b]) must[i]=1; } for (ll i=1;i<=m;i++){ if (must[i]) continue; ll a=frm[0][i],b=son[0][i]; ans[i]=mindis-dis[0][a]-dis[1][b]-1; } for (ll i=1;i<=m;i++){ if (must[i]) puts("YES"); else if (ans[i]>0) printf("CAN %I64d\n",val[0][i]-ans[i]); else puts("NO"); } } int main(){ scanf("%I64d%I64d%I64d%I64d",&n,&m,&st,&ed);tot[2]=1; for (ll i=1,a,b,c;i<=m;i++) scanf("%I64d%I64d%I64d",&a,&b,&c),add(a,b,c,0),add(b,a,c,1); dijkstra(0),dijkstra(1),rebuild(),tarjan(st,0),work(); return 0; }