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


转载于:https://www.cnblogs.com/thythy/p/5493519.html

Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值