ZR金华集训D2T3

[ZR金华集训D2T3 完美理论]

又是一道看上去一点不像网络流的题目呢

我们分析一下问题,就会发现许多神奇的性质。

因为题目中要求的是联通块

也就是说,我们假设强制跟必须选,想原则\(x\),那么\(x\)到根这一条链上的点都必须选

换句话说,有依赖关系

想到了什么

最大权闭合子图!

将所有点权分成正负两部分划分\(S\)\(T\)集合

所以我们枚举\(x\)点强制选,在两颗树中分别dfs

给所有儿子向其父亲连一条权值为\(\infty\)的边

跑最小割更新答案就好了

#include<cstdio> 
#include<cctype>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N = 1e3 + 3;
int n,m,tot = 1;
int head[N],cur[N];
const int INF =  2e9;
int high[N],a[N],f1[N],f2[N];
int sum,s,t,ans = INF;
struct edge{
	int to;
	int nxt;
	int flow;	
}e[N << 2];
vector <int> G1[N],G2[N];
inline int read(){
	int v = 0,c = 1;char ch = getchar();
	while(!isdigit(ch)){
		if(ch == '-') c = -1;
		ch = getchar();	
	}
	while(isdigit(ch)){
		v = v * 10 + ch - 48;
		ch = getchar();	
	}
	return v * c;	
}
inline void add(int x,int y,int flow){
	e[++tot].to = y;
	e[tot].flow = flow;
	e[tot].nxt = head[x];
	head[x] = tot;
}
inline void dfs1(int x,int f){
	f1[x] = f;
	for(int i = 0;i < (int)G1[x].size();++i){
		int y = G1[x][i];
		if(y == f) continue;
		add(y,x,INF);
		add(x,y,0);
		dfs1(y,x); 	
	}
}
inline void dfs2(int x,int f){
	f2[x] = f;
	for(int i = 0;i < (int)G2[x].size();++i){
		int y = G2[x][i];
		if(y == f) continue;
		add(y,x,INF);
		add(x,y,0);
		dfs2(y,x); 	
	}
}
inline bool bfs(){
	queue <int> q;
	for(int i = 1;i <= n + 2;++i) high[i] = 0;	
	q.push(s);high[s] = 1;
	while(!q.empty()){
		int k = q.front();q.pop();
		for(int i = head[k];i;i = e[i].nxt){
			int y = e[i].to;
			if(!high[y] && e[i].flow > 0)
			high[y] = high[k] + 1,q.push(y);
		}
	}
	return high[t] != 0;
}
int dfs(int x,int dis){
	if(x == t) return dis;
	for(int &i = cur[x];i;i = e[i].nxt){
		int y = e[i].to;
		if(high[y] == high[x] + 1 && e[i].flow > 0){
			int  flow = dfs(y,min(dis,e[i].flow));
			if(flow > 0){
				e[i].flow -= flow;
				e[i ^ 1].flow += flow;
				return flow;
			}
		}
	}
	return 0;
}
inline int dinic(){
	int res = 0;
	while(bfs()){
		for(int i = 1;i <= n + 2;++i) cur[i] = head[i];
		while(int now = dfs(s,INF))
			res += now;
	}
	return res;
}
int main(){
	int T = read();
	while(T--){
	ans = INF,sum = 0;
	n = read();
	s = n + 1,t = n + 2; 
	for(int i = 1;i <= n;++i){
		a[i] = read();	
		if(a[i] > 0) sum += a[i];
		G1[i].clear();
		G2[i].clear();
	}
	G1[s].clear(),G2[s].clear(),G1[t].clear(),G2[t].clear();
	for(int i = 1;i < n;++i){
		int x = read(),y = read();
		G1[x].push_back(y);
		G1[y].push_back(x);	
	}
	for(int i = 1;i < n;++i){
		int x = read(),y = read();
		G2[x].push_back(y);
		G2[y].push_back(x);	
	}
	for(int i = 1;i <= n;++i){
		if(a[i] < 0) continue;
		for(int j = 1;j <= n + 2;++j) head[j] = 0; tot = 1;
		dfs1(i,0);dfs2(i,0);
		for(int j = 1;j <= n;++j){
			if(a[j] > 0) add(s,j,a[j]),add(j,s,0);
			else add(j,t,-a[j]),add(t,j,0);
		}
		ans = min(ans,dinic());
	}
	if(ans == INF) ans = 0;
	printf("%d\n",sum - ans);
	}

	return 0;
}
posted @ 2019-04-01 21:08  wyxdrqcccc  阅读(26)  评论(0编辑  收藏  举报