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
",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
",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
",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;
}


原文地址:https://www.cnblogs.com/thythy/p/5493519.html