[国家集训队]阿狸和桃子的游戏

对于两点之间的边是不好处理的,但基于观察可以发现:双方都只会将点染色,因此我们的想法是将边权放到点权上去然后构造出一种选择点权的方案与原问题等价。

同时,因为对于一条边而言它连接的两点代价是一致的,因此下放点权的过程应该满足对称性。

此时基于观察可以发现:

  • \(\forall (u, v, w)\) 如果下放到 \(u, v\) 的点权满足对称性即相等,则如果 \(u, v\) 没有同时被一个人选择那么边权将会恰好抵消满足题意。

那么我们只需要调整下方的大小使得当 \(u, v\) 同时被选时获得的权值恰好边权即可。

不难发现有且仅有 \(\frac{w}{2}\) 满足要求。

但因为 \(w\) 可能为奇数不方便计算,因此我们开始将所有权值扩大一倍最后将答案减半即可。

于是问题就被转化为:先手后手每次可以取一个点获得这个点的点权,问对抗博弈后先手减后手的得分。

不难发现此时先后手的策略都一定是取每次剩下的最大值,排序一遍即可,复杂度 \(O(n \log n + m)\)

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 10000 + 5;
int n, m, u, v, w, ans, a[N];
int read() {
    char c; int x = 0, f = 1;
    c = getchar();
    while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
signed main() {
    n = read(), m = read();
    rep(i, 1, n) a[i] = read() * 2;
    rep(i, 1, m) u = read(), v = read(), w = read(), a[u] += w, a[v] += w;
    sort(a + 1, a + n + 1);
    for (int i = n, j = 1; i >= 1; --i, j = -j) ans += j * a[i];
    printf("%d", ans / 2);
    return 0;
}
posted @ 2020-10-23 18:44  Achtoria  阅读(75)  评论(0编辑  收藏  举报