$d_1(x)$:从 $s_1$ 到 $x$ 的距离。
$d_2(x)$:从 $s_2$ 到 $x$ 的距离。
我们将一条边 $(a,b)$ 的权值只可能调整到 $l_i$ 或 $r_i$,考虑以下三种情况:
- 这条边没有被任何人经过
不影响答案。
- 这条边被 A 经过但没有被 B 经过
因为 B 之前没有选择走这条边,一定有 $d_1(a) < d_2(a)$ ,所以如果在这之后 B 选择走这条边 $d_1(t) = d_1(a)+dis(a,b)+dis(b,t)$ 也一定小于 $d_2(t) = d_2(a) + dis(a,b) + dis(b,t) $,如果 B 不选择走这条边,$d_1(t)$ 减小而 $d_2(t)$ 没有变化。
-
这条边被 A,B 同时经过
$d_1(t)$ 和 $d_2(t)$ 减小同样的数值。
(这里只考虑调小,调大同理)
那么我们有一种做法,首先把所有边权设为 $r_i$,然后对于每一条边,如果有 $d_1(a) < d_2(a)$,那么将它的边权设为 $l_i$,最后判断 $d_1(t)$ 是否小于 $d_2(t)$,如果不是则所有边权设为 $r_i$ 再来一次,如果有 $d_1(a) \le d_2(a)$,那么将它的边权设为 $l_i$,最后判断$d_1(t)$ 是否小于等于 $d_2(t)$ 即可。
考虑这种做法的正确性,
- 如果一条边满足 $d_1(a) < d_2(a)$,则之后对边权的改变不会影响这个性质
考虑反证,如果在改变 $(a_2,b_2)$ 后 $d_2(a_1) \le d_1(a_1)$,因为我们只改变了一条边就使 $d_2(a_1)$ 减小了,那么 $(a_2,b_2)$ 一定在 $s_2$ 到 $a_1$ 的最短路上,那么 $d_2(a_1)=d_2(a_2)+dis(a_2,b_2)+dis(a_2,a_1)$ 大于 $d_1(a_1)=d_1(a_2)+dis(a_2,b_2)+dis(a_2,a_1)$,矛盾。
- 所以在最后所有边权为 $l_i$ 的边都会满足 $d_1(a) < d_2(a)$,而其他的边在任何可能的边权下都会有 $d_1(a) \ge d_2(a)$(即对答案没有正面贡献)
// 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;
}