swift's blog

swift's blog

CF360E Levko and Game 题解

posted on 2021-08-12 16:02:03 | under 题解 |

$d_1(x)$:从 $s_1$ 到 $x$ 的距离。

$d_2(x)$:从 $s_2$ 到 $x$ 的距离。

我们将一条边 $(a,b)$ 的权值只可能调整到 $l_i$ 或 $r_i$,考虑以下三种情况:

  1. 这条边没有被任何人经过

不影响答案。

  1. 这条边被 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)$ 没有变化。

  1. 这条边被 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)$ 即可。

考虑这种做法的正确性,

  1. 如果一条边满足 $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)$,矛盾。

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