题目
题面
给出节点个数为(n)两棵树,点的权值都相同为(a_i);
要求选出一些点(S),使得在两颗树上都是一个连通块;
最大化(S)的点权;
(T)组数据;
范围
$1 le T le 50 , 1 le n le 100 , |a_i| le 1000 $;
题解
-
典型的网络流范围;
-
确定一个根之后,选一个点必须选一个点的父亲;
-
做最大权闭合子图即可;
-
复杂度:(O(Tn^4));
#include<bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; const int N=410; int n,m,a[N],o,hd[N],preO,preH[N],cur[N],vis[N],d[N],ans; struct Edge{int v,nt,f;}E[N<<1],preE[N<<1]; queue<int>q; char gc(){ static char*p1,*p2,s[1000000]; if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); return(p1==p2)?EOF:*p1++; } int rd(){ int x=0,f=1;char c=gc(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=gc();} return x*f; } void init(){ o=preO;for(int i=0;i<=n+1;++i)hd[i]=preH[i]; for(int i=0;i<o;++i)E[i]=preE[i]; } void adde(int u,int v,int c){ E[o]=(Edge){v,hd[u],c};hd[u]=o++; E[o]=(Edge){u,hd[v],0};hd[v]=o++; } struct Tree{ int o,hd[N],fa[N]; struct Edge{int v,nt;}E[N<<1]; void init(){o=1;for(int i=1;i<=n;++i)hd[i]=0;} void adde(int u,int v){ E[o]=(Edge){v,hd[u]};hd[u]=o++; E[o]=(Edge){u,hd[v]};hd[v]=o++; } void dfs(int u,int F){ fa[u]=F; for(int i=hd[u];i;i=E[i].nt){ int v=E[i].v; if(v==F)continue; dfs(v,u); } } }T1,T2; bool bfs(){ for(int i=0;i<=n+1;++i)vis[i]=d[i]=0; while(!q.empty())q.pop(); q.push(0);vis[0]=d[0]=1; while(!q.empty()){ int u=q.front();q.pop(); for(int i=hd[u];~i;i=E[i].nt)if(E[i].f){ int v=E[i].v; if(vis[v])continue; vis[v]=1;d[v]=d[u]+1;q.push(v); if(v==n+1)return true; } } return false; } int dfs(int u,int F){ if(u==n+1||!F)return F; int flow=0,f; for(int i=cur[u];~i;i=E[i].nt){ int v=E[cur[u]=i].v; if(d[v]==d[u]+1&&(f=dfs(v,min(E[i].f,F)))){ flow+=f;F-=f; E[i].f-=f;E[i^1].f+=f; if(!F)break; } } return flow; } int main(){ // freopen("noname.in","r",stdin); // freopen("noname.out","w",stdout); int T=rd(); while(T--){ n=rd(); o=0;for(int i=0;i<=n+1;++i)hd[i]=-1; int preAns=0; for(int i=1;i<=n;++i){ a[i]=rd(); if(a[i]<0)adde(i,n+1,-a[i]); else adde(0,i,a[i]),preAns+=a[i]; } preO=o;for(int i=0;i<=n+1;++i)preH[i]=hd[i]; for(int i=0;i<o;++i)preE[i]=E[i]; T1.init();for(int i=1;i<n;++i)T1.adde(rd(),rd()); T2.init();for(int i=1;i<n;++i)T2.adde(rd(),rd()); ans=0; for(int i=1;i<=n;++i){ init(); T1.dfs(i,0); T2.dfs(i,0); for(int i=1;i<=n;++i){ adde(i,T1.fa[i],inf); adde(i,T2.fa[i],inf); } int tmp=preAns; while(bfs()){ for(int i=0;i<=n+1;++i)cur[i]=hd[i]; tmp-=dfs(0,inf); } ans=max(ans,tmp); } printf("%d ",ans); } return 0; }