Description
有两颗各含N个点的无根树,每棵树中点分别被编号为0,1,2,…,N-1;注意两棵树并不保证同构。
另外给一个N长的整数数组Score[],记录N个编号的得分,Score中的每个元素可正可负。
问题的任务是寻找 集合{0,1,2,3,4,…,N-1}的一个最优子集subset,要求满足以下条件:
1)在第一棵树中,subset中包含的编号对应的点能构成一个连通的子图;即去掉这棵树中所有subset中不包含的点后,剩下的点依然是一棵连通的树。
2)在第二棵树中,subset中包含的编号对应的点也能构成一个连通的子图;
3)使subset包含编号的总得分尽可能的大;即SUM{ Score[i] | i∈subset }能取到尽可能大的值。
输出这个subset包含编号的总分的最大值。
Solution
一直在想要怎么保证选出来的点连通
我们枚举一个必选的点,并把这个点作为根,那么其余选出来的点必定是若干条链的并
也就是说,我们选择一个点必须要选择它到根路径上的所有点,这个限制就比较强了。。
然后就是最大权闭合子图了,最小割就行了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int INF=0x3f3f3f3f;
const int E=500005;
const int N=200005;
struct edge {int x,y,w,next;} ;
struct Tree {
edge e[E];
int ls[N],edCnt;
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,0,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,0,ls[y]}; ls[y]=edCnt;
}
} T1,T2;
edge e[E];
int dis[N],ls[N],w[N],edCnt;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y,int w) {
e[++edCnt]=(edge) {x,y,w,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,0,ls[y]}; ls[y]=edCnt;
}
bool bfs(int st,int ed) {
std:: queue <int> que;
que.push(st);
rep(i,st,ed) dis[i]=0;
dis[st]=1;
for (;!que.empty();) {
int x=que.front(); que.pop();
for (int i=ls[x];i;i=e[i].next) {
if (e[i].w>0&&!dis[e[i].y]) {
dis[e[i].y]=dis[x]+1;
if (e[i].y==ed) return true;
que.push(e[i].y);
}
}
}
return false;
}
int find(int x,int ed,int mn) {
if (x==ed||!mn) return mn;
int ret=0;
for (int i=ls[x];i;i=e[i].next) {
if (e[i].w>0&&dis[x]+1==dis[e[i].y]) {
int d=find(e[i].y,ed,std:: min(mn-ret,e[i].w));
e[i].w-=d; e[i^1].w+=d; ret+=d;
if (mn==ret) break;
}
}
return ret;
}
int dinic(int st,int ed) {
int res=0;
for (;bfs(st,ed);) res+=find(st,ed,INF);
return res;
}
void dfs1(int x,int fa) {
if (fa) add_edge(fa,x,INF);
for (int i=T1.ls[x];i;i=T1.e[i].next) {
if (T1.e[i].y==fa) continue;
dfs1(T1.e[i].y,x);
}
}
void dfs2(int x,int fa) {
if (fa) add_edge(fa,x,INF);
for (int i=T2.ls[x];i;i=T2.e[i].next) {
if (T2.e[i].y==fa) continue;
dfs2(T2.e[i].y,x);
}
}
void build(int n,int rt) {
rep(i,0,n+1) ls[i]=0; edCnt=1;
dfs1(rt,0); dfs2(rt,0);
}
int main(void) {
freopen("data.in","r",stdin);
int n=read(),sum=0,ans=0;
rep(i,1,n) w[i]=read(),sum+=(w[i]>0)*w[i];
rep(i,2,n) T1.add_edge(1+read(),1+read());
rep(i,2,n) T2.add_edge(1+read(),1+read());
rep(rt,1,n) {
build(n,rt);
rep(i,1,n) if (w[i]<0) add_edge(0,i,-w[i]);
else add_edge(i,n+1,w[i]);
ans=std:: max(ans,sum-dinic(0,n+1));
}
printf("%d\n", ans);
return 0;
}