arc107F - Sum of Abs

题目大意

给出一个无向图,可以删掉若干点,删i的代价是ai,最大化Σ|剩余连通块bi之和|-代价

n,m<=300

题解

看错题后的版本:每删掉一个点对其相连连通块计算贡献,使最后和最大

完全不可做


先删掉一些点,对剩下的一个块里的贡献同为+1或-1,则可以转化为对每个点赋+1/-1/删掉,最终贡献为bi*点权之和,且有边相连的点的权相同

先加上Σ|bi|,接下来用最小割使其合法

连S->i1->i2->T,对应+1/删/-1,若bi>=0则为0/bi+ai/2bi,<0则为2|bi|/|bi|+ai/0

如果一个点被删掉了,那么其他点和其的限制会消失,所以对于(u,v)直接连v2->u1和u2->v1的inf边即可

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define abs(x) ((x)>0?(x):-(x))
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define inf 100000000
#define ll long long
//#define file
using namespace std;

int a[100001][3],ls[701],cur[701],A[301],B[301],f[701],g[701],n,m,i,j,k,l,len,ans,st,ed;

void NEW(int x,int y,int z) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;a[len][2]=z;}
void New(int x,int y,int z) {NEW(x,y,z),NEW(y,x,0);}

int dfs(int t,int flow)
{
	int i,use=0,w;
	if (t==ed) return flow;
	
	for (i=cur[t]; i; i=a[i][1])
	{
		cur[t]=i;
		if (a[i][2] && f[t]==f[a[i][0]]+1)
		{
			w=dfs(a[i][0],min(a[i][2],flow-use)),use+=w;
			a[i][2]-=w,a[i^1][2]+=w;
			if (use==flow) return use;
		}
	}
	cur[t]=ls[t];
	
	--g[f[t]];
	if (!g[f[t]]) {f[st]=ed+1;return use;}
	++f[t],++g[f[t]];
	return use;
}

int main()
{
	#ifdef file
	freopen("f.in","r",stdin);
	#endif
	
	scanf("%d%d",&n,&m),len=1;st=n*2+1,ed=n*2+2;
	fo(i,1,n) scanf("%d",&A[i]);
	fo(i,1,n) scanf("%d",&B[i]),ans+=abs(B[i]);
	fo(i,1,n)
	if (B[i]>=0)
	New(st,i*2-1,0),New(i*2-1,i*2,abs(B[i])+A[i]),New(i*2,ed,2*abs(B[i]));
	else
	New(st,i*2-1,2*abs(B[i])),New(i*2-1,i*2,abs(B[i])+A[i]),New(i*2,ed,0);
	fo(i,1,m) scanf("%d%d",&j,&k),New(j*2,k*2-1,inf),New(k*2,j*2-1,inf);
	
	g[0]=ed;
	while (f[st]<=ed) ans-=dfs(st,inf);
	printf("%d\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-11-01 09:02  gmh77  阅读(295)  评论(0编辑  收藏  举报