「题解」Codeforces 360E Levko and Game

「题解」Codeforces 360E Levko and Game

现在明确我们的目的:能赢就选择赢的方案,否则尝试平局;并不是求和对方差值更大的方案。

考虑一个赢/平局的方案,考虑每一条边,没有被任何一个经过,那么调整到任何值都是无所谓的;如果仅被 s1 经过,调整到 l 是更优的;如果仅被 s2 经过,调整到 r 是更优的;如果同时被 s1,s2 经过,那么一定是一个平局的方案,把这条边改得更小还会使 s1,s2 经过这里,如果把这条边改得更大反而可能让 s1,s2 走其他路从而变成一个 s1 赢的方案,如果不存在让 s1 赢的方案再把它改成 l ,也就是尽可能地让 s1,s2 一起走到这里,促成平局。

综上所述,一定存在一个最优方案使得每条边的权值要不然为 l,要不然为 r

考虑如何让 s1 赢:对于一条边 (u,v)

  • dis(s1,u)dis(s2,u),那么 s1 一定不会走这条路,因为走到这条路之后和 s2 的最优路线重合,一定不会赢,所以改成 rs2 走这条路的开销更大;

  • dis(s1,u)<dis(s1,u),同理,s2 走这条路会使 s1 赢,那么 s2 不会走这条路,改成 ls1 走这条路的开销更小。

现在判断完了 s1 能不能赢,如果不能赢就尽可能平局,和上面的思路基本一致:

  • dis(s1,u)>dis(s2,u),那么 s1 一定不会走这条路,因为走到这条路之后和 s2 的最优路线重合,一定不会平局,所以改成 rs2 走这条路的开销更大;

  • dis(s1,u)dis(s1,u),同理,s2 走这条路会平局或 s1 赢 ,那么 s2 不会走这条路,改成 ls1 走这条路的开销更小。

先钦点所有的边都是 r,每次跑 Dijkstra 然后看哪些边要改权值就改,没有边权值要改时再判断,易做到 O(kmlogn)

实际上可以在最短路每次松弛的时候判断当前边的权值是多少,时间复杂度 O(mlogn)

Code

#include<iostream>
#include<cstdio>
#include<queue>
#define int long long 
typedef long long ll;
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T& read(T& r) {
	r = 0; bool w = 0; char ch = getchar();
	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
	return r = w ? -r : r;
}
const int N = 200010;
const ll INF = 0x7fffffffffffffff;
int n, m, k;
int s1, s2, t;
ll dis[N];
struct Edge {
	int to, val1, val2, id;
	bool fl;
	Edge(int x = 0, int y = 0, int z = 0, int p = 0) { to = x; val1 = y; val2 = z; id = p; }
};
int ans[N];
std::vector<Edge>vec[N];
std::queue<int>q;
void Dij(int s1, int s2, int fl) {
	for(int i = 1; i <= n; ++i) dis[i] = INF;
	dis[s1] = 1; dis[s2] = 0;
	q.push(s1); q.push(s2);
	while(!q.empty()) {
		int x = q.front(); q.pop();
		for(Edge &e : vec[x]) {
			int v = e.to, w = (e.fl = ((dis[x]&1) == fl)) ? e.val1 : e.val2;
			if(dis[v] > dis[x] + w) {
				dis[v] = dis[x] + w;
				q.push(v);
			}
		}
	}
}
signed main() {
	read(n); read(m); read(k);
	read(s1); read(s2); read(t);
	for(int i = 1; i <= m; ++i) {
		int u, v, l; read(u); read(v); read(l);
		vec[u].push_back(Edge(v, l<<1, l<<1, 0));
	}
	for(int i = 1; i <= k; ++i) {
		int u, v, l, r; read(u); read(v); read(l); read(r);
		vec[u].push_back(Edge(v, l<<1, r<<1, i));
	}
	Dij(s1, s2, 1);
	if(dis[t] & 1) {
		puts("WIN");
		for(int i = 1; i <= n; ++i)
			for(Edge e : vec[i])
				ans[e.id] = e.fl ? e.val1 : e.val2;
		for(int i = 1; i <= k; ++i) printf("%lld ", ans[i]/2);
	}
	else {
		Dij(s2, s1, 0);
		if(!(dis[t]&1)) {
			puts("DRAW");
			for(int i = 1; i <= n; ++i)
				for(Edge e : vec[i])
					ans[e.id] = e.fl ? e.val1 : e.val2;
			for(int i = 1; i <= k; ++i) printf("%lld ", ans[i]/2);
		}
		else {
			puts("LOSE");
		}
	}
	return 0;
}
posted @   do_while_true  阅读(34)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?

This blog has running: 1845 days 1 hours 33 minutes 33 seconds

点击右上角即可分享
微信分享提示