传送门
题解:
太久没写网络流了,连加边都写错了,居然还TM过了80%的点,出题人该被拖出去阿鲁巴
很显然这是一个冲突建模,由于数据范围实在太小,我们考虑枚举每一个点必选,然后它作为根,那么限制条件就很明显了,选了节点 u u u就必须选节点 u u u的父亲,然后最大化所有选了点的权值和。
显然是最大权闭合子图。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int N=55,INF=0x3f3f3f3f;
int n,S,T;
namespace Net_Work{
struct edge{
int to,cap,rev;
edge(int _to,int _cap,int _rev):to(_to),cap(_cap),rev(_rev){}
};
std::vector<edge> G[N];
typedef std::vector<edge>::iterator iter;
iter cur[N];
void addedge(int u,int v,int val){
G[u].push_back(edge(v,val,G[v].size()));
G[v].push_back(edge(u,0,G[u].size()-1));
}
int lev[N],gap[N];
void BFS(){
memset(lev,-1,sizeof(int)*(n+2));
memset(gap,0,sizeof(int)*(n+2));
lev[T]=gap[1]=1;
std::queue<int> q;
q.push(T);
while(!q.empty()){
int u=q.front();q.pop();
for(iter re e=G[u].begin();e!=G[u].end();++e)if(!~lev[e->to]){
q.push(e->to);
++gap[lev[e->to]=lev[u]+1];
}
}
}
int dfs(int u,cs int &flow){
if(u==T)return flow;
int ans=0;
for(iter &e=cur[u];e!=G[u].end();++e)
if(e->cap&&lev[e->to]+1==lev[u]){
int delta=dfs(e->to,std::min(flow-ans,e->cap));
if(delta){
e->cap-=delta;
G[e->to][e->rev].cap+=delta;
ans+=delta;
if(ans==flow)return ans;
}
}
if(!--gap[lev[u]])lev[S]=n+1;
++gap[++lev[u]];
return ans;
}
int ISAP(){
int flow=0;BFS();
while(lev[S]<=n){
for(int re i=0;i<=n+1;++i)cur[i]=G[i].begin();
flow+=dfs(S,INF);
}
return flow;
}
void clear(){for(int re i=0;i<=n+1;++i)G[i].clear();}
}
namespace A{
std::vector<int> G[N];
void addedge(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
void dfs(int u,int fa){
if(fa)Net_Work::addedge(u,fa,INF);
for(int re v:G[u])if(v!=fa)dfs(v,u);
}
}
namespace B{
std::vector<int> G[N];
void addedge(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
void dfs(int u,int fa){
if(fa)Net_Work::addedge(u,fa,INF);
for(int re v:G[u])if(v!=fa)dfs(v,u);
}
}
int v[N];
int sum,ans;
signed main(){
// freopen("tree.in","r",stdin);
scanf("%d",&n);S=0,T=n+1;
for(int re i=1;i<=n;++i)scanf("%d",&v[i]);
for(int re i=1;i<n;++i){int u,v;scanf("%d%d",&u,&v);A::addedge(u+1,v+1);}
for(int re i=1;i<n;++i){int u,v;scanf("%d%d",&u,&v);B::addedge(u+1,v+1);}
for(int re i=1;i<=n;++i){
Net_Work::clear();
A::dfs(i,0);B::dfs(i,0);sum=0;
for(int re i=1;i<=n;++i)if(v[i]>0)Net_Work::addedge(S,i,v[i]),sum+=v[i];
else Net_Work::addedge(i,T,-v[i]);
sum-=Net_Work::ISAP();
ans=std::max(ans,sum);
}
cout<<ans<<"\n";
return 0;
}