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

传送门

这题看一眼就很不可做

考虑对于任意一个最终状态,对于一条边的贡献分成三种情况

如果此边连接的两点属于 $A$,那么对 $A$ 的贡献就是边权 $w$,即对答案的贡献为 $+w$

如果两点都属于 $B$,对 $B$ 的贡献就是边权 $w$,对答案的贡献为 $-w$

如果两点属于两人,那么对答案的贡献为 $0$

考虑固定所有点的贡献,发现如果把点权加上所有与它相邻边的边权除二

那么如果此边两点都是同一个人则对答案的贡献也还是 $+-w$

如果两点属于不同一个人,那么边的价值恰好抵消,对答案的贡献为 $0$

所以如果把点权这样改变,对于任意最终状态,每个点的贡献在一开始就被固定了

那么我们可以直接把点权变一下,然后模拟从大到小轮流选就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=1e5+7;
int n,m,v[N];
ll ans;
int main()
{
    n=read(),m=read(); int a,b,c;
    for(int i=1;i<=n;i++) v[i]=read()*2;
    for(int i=1;i<=m;i++)
    {
        a=read(),b=read(),c=read();
        v[a]+=c; v[b]+=c;
    }
    sort(v+1,v+n+1);
    for(int i=1;i<=n;i++)
        ans+=(i&1 ? -1 : 1)*v[i];
    printf("%lld
",ans/2);
    return 0;
}
原文地址:https://www.cnblogs.com/LLTYYC/p/11349017.html