CF360E Levko and Game 题解
:从 到 的距离。
:从 到 的距离。
我们将一条边 的权值只可能调整到 或 ,考虑以下三种情况:
- 这条边没有被任何人经过
不影响答案。
- 这条边被 A 经过但没有被 B 经过
因为 B 之前没有选择走这条边,一定有 ,所以如果在这之后 B 选择走这条边 也一定小于 ,如果 B 不选择走这条边, 减小而 没有变化。
- 这条边被 A,B 同时经过
和 减小同样的数值。
(这里只考虑调小,调大同理)
那么我们有一种做法,首先把所有边权设为 ,然后对于每一条边,如果有 ,那么将它的边权设为 ,最后判断 是否小于 ,如果不是则所有边权设为 再来一次,如果有 ,那么将它的边权设为 ,最后判断 是否小于等于 即可。
考虑这种做法的正确性,
- 如果一条边满足 ,则之后对边权的改变不会影响这个性质
考虑反证,如果在改变 后 ,因为我们只改变了一条边就使 减小了,那么 一定在 到 的最短路上,那么 大于 ,矛盾。
- 所以在最后所有边权为 的边都会满足 ,而其他的边在任何可能的边权下都会有 (即对答案没有正面贡献)
// Problem: CF360E Levko and Game
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF360E
// Memory Limit: 250 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define N 100000
#define int long long
using namespace std;
int n, m, k, s1, s2, f, head[N], nxt[N], to[N], cnt, s[N], t[N], l[N], r[N],
v[N], d1[N], d2[N];
int *len[N];
void add(int a, int b, int *l) {
nxt[++cnt] = head[a];
to[cnt] = b;
len[cnt] = l;
head[a] = cnt;
}
struct node {
int x, v;
node(int _x, int _v) : x(_x), v(_v) {}
bool operator<(const node &t) const { return v > t.v; }
};
void dij(int s, int *dis) {
memset(dis, 0x3f, sizeof(int) * (n + 1));
priority_queue<node> p;
dis[s] = 0;
p.emplace(s, 0);
while (!p.empty()) {
node x = p.top();
p.pop();
if (dis[x.x] != x.v) continue;
for (int i = head[x.x]; i; i = nxt[i]) {
if (dis[to[i]] > dis[x.x] + *len[i]) {
dis[to[i]] = dis[x.x] + *len[i];
p.emplace(to[i], dis[to[i]]);
}
}
}
}
bool solve(int d) {
bool flag = false;
do {
flag = false;
dij(s1, d1);
dij(s2, d2);
for (int i = 1; i <= k; i++) {
if (v[i] == r[i] && d1[s[i]] < d2[s[i]] + d) {
v[i] = l[i];
flag = 1;
}
}
} while (flag);
return d1[f] < d2[f] + d;
}
signed main() {
cin >> n >> m >> k;
cin >> s1 >> s2 >> f;
for (int i = 1; i <= m; i++) {
int a, b, l;
cin >> a >> b >> l;
add(a, b, new int(l));
}
for (int i = 1; i <= k; i++) {
cin >> s[i] >> t[i] >> l[i] >> r[i];
v[i] = r[i];
add(s[i], t[i], &v[i]);
}
for (int i = 1; i <= k; i++) {
dij(s1, d1);
dij(s2, d2);
if (d1[s[i]] < d2[s[i]]) {
v[i] = l[i];
}
}
if (solve(0)) {
puts("WIN");
for (int i = 1; i <= k; i++) {
cout << v[i] << " ";
}
return 0;
}
if (solve(1)) {
puts("DRAW");
for (int i = 1; i <= k; i++) {
cout << v[i] << " ";
}
return 0;
}
puts("LOSE");
return 0;
}

浙公网安备 33010602011771号