BZOJ 2563 阿狸和桃子的游戏
题意
给出一个图,每个点有点权(v_i),每条边有边权(c_i),两个人轮流选点,选择一个点可以获得这个点的点权,一条边的两个点如果都被一个人选了,那么这个人会获得这条边的边权。两者都采取最优的方案,问后手的分数减先手的分数是多少。
题解
看了题解之后感觉这道题目好妙啊。我们先分析对于一个人对一个点的选择对答案造成的影响:
1.如果一个点被这个人选择了,那么它的贡献是(v_i),如果这个点没有被选择,那么他的贡献是(-v_i)。
2.如果一条边的两个端点都被这个人选择了,那么它的贡献是(c_i),如果分别被两个人选择了,那么它的贡献是(0),如果都被另一个人选择了,那么它的贡献是(-c_i)。
而题目要我们求的两者的分数差,于是我们可以将(ans)减去所有的贡献,先默认由先手选择了,于是后手的选择对答案的影响会变成这样:
1.如果一个点被这个人选择了,那么它的贡献是(2v_i),否则贡献是(0)。
2.如果一条边的两个端点都被这个人选择了,那么它的贡献是(2c_i),如果分别被两个人选择了,那么它的贡献是(c_i),如果都被另一个人选择了,那么它的贡献是(0)。
这样做了改变之后,我们就可以把一个点的点权改为(2v_i+sum_{e=(i,v)} c(e)),那么选择了这个点之后,获得的贡献仍然还是和之前一样的,并且不用考虑边权。然后我们就可以贪心的选择点,最后统计一下答案即可。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('
');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
#define PAUSE printf("Press Enter key to continue..."); fgetc(stdin);
const int N=1e5+500;
int n,m;
int val[N];
int ans=0;
/*==================Define Area================*/
int main() {
read(n);read(m);
for(int i=1;i<=n;i++) read(val[i]),ans-=val[i],val[i]*=2;
for(int i=1,u,v,c;i<=m;i++) read(u),read(v),read(c),ans-=c,val[u]+=c,val[v]+=c;
sort(val+1,val+1+n);
for(int i=2;i<=n;i+=2) ans+=val[i];
printf("%d
",ans);
return 0;
}