首先如果点权全都为正,就可以直接选所有的点。

活在梦里。。

考虑枚举一个点\(i\),作为我们选择的集合中的一个点。

然后我们把另一个点\(j\)选入集合的时候必须把两棵树中\(i\)和\(j\)路径上的点全都选入集合。

似乎想到了什么。

闭合子图。

不就是一个最大权闭合子图吗。

然后我们按最大权闭合子图的模型建图。

所有正权的点跟\(S\)连容量为权值的边。

所有负权的点跟\(T\)连容量为权值绝对值的边。

我们把枚举的i作为两个树上的根。

然后每一个点跟两颗树上的\(father\)连容量为\(INF\)的边。

然后正权总和-最小割就是答案。

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=1e9;
const int N=110;
int cnt,head[N];
struct edge{
int to,nxt,flow;
}e[N*6];
void add_edge(int u,int v,int flow){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
e[cnt].flow=flow;
}
int cn,hed[N];
struct ed{
int to,nxt;
}ee[N*2];
void add(int u,int v){
cn++;
ee[cn].nxt=hed[u];
ee[cn].to=v;
hed[u]=cn;
}
int f1[N];
void dfs1(int u,int f){
f1[u]=f;
for(int i=hed[u];i;i=ee[i].nxt){
int v=ee[i].to;
if(v==f)continue;
dfs1(v,u);
}
}
int f2[N];
void dfs2(int u,int f){
f2[u]=f;
for(int i=hed[u];i;i=ee[i].nxt){
int v=ee[i].to;
if(v==f)continue;
dfs2(v,u);
}
}
int dis[N],S,T;
bool bfs(){
memset(dis,-1,sizeof(dis));
dis[S]=0;
queue<int> q;
q.push(S);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[v]==-1&&e[i].flow){
dis[v]=dis[u]+1;
q.push(v);
}
}
}
if(dis[T]==-1)return false;
return true;
}
int dfs(int u,int f){
if(u==T||f==0)return f;
int used=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[v]==dis[u]+1&&e[i].flow){
int w=dfs(v,min(f-used,e[i].flow));
if(w){
e[i].flow-=w;
e[i^1].flow+=w;
used+=w;
if(used==f)return f;
}
}
}
if(used==0)dis[u]=-1;
return used;
}
int tmp;
void Dinic(){
while(bfs())tmp+=dfs(S,INF);
}
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum*f;;
}
int n,a[N],tot,ans;
int main(){
n=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<n;i++){
int u=read()+1,v=read()+1;
add(u,v);add(v,u);
}
for(int i=1;i<n;i++){
int u=read()+n+1,v=read()+n+1;
add(u,v);add(v,u);
}
for(int i=1;i<=n;i++){
dfs1(i,0);dfs2(i+n,0);
cnt=1;memset(head,0,sizeof(head));tot=0;
S=0,T=n+1;
for(int j=1;j<=n;j++)
if(a[j]<0)add_edge(j,T,-a[j]),add_edge(T,j,0);
else add_edge(S,j,a[j]),add_edge(j,S,0),tot+=a[j];
for(int j=1;j<=n;j++){
if(j==i)continue;
add_edge(j,f1[j],INF);add_edge(f1[j],j,0);
add_edge(j,f2[j+n]-n,INF);add_edge(f2[j+n]-n,j,0);
}
tmp=0;
Dinic();
ans=max(ans,tot-tmp);
}
printf("%d",ans);
return 0;
}

51nod 1325 两棵树的问题(最大权闭合子图)的更多相关文章

  1. 51 NOD 1325 两棵树的问题

    Discription 对于 100% 的数据, N<=50. solution: 发现N比较小,所以我们可以花O(N^2)的代价枚举两颗树的联通块的LCA分别是哪个点,然后现在问题就变成了:选 ...

  2. LeetCode——Same Tree(判断两棵树是否相同)

    问题: Given two binary trees, write a function to check if they are equal or not. Two binary trees are ...

  3. WPF的两棵树与绑定

    原文:WPF的两棵树与绑定   先建立测试基类 public class VisualPanel : FrameworkElement { protected VisualCollection Chi ...

  4. element ui改写实现两棵树

    使用element ui组件库实现一个table的两棵树的效果 效果如下,左边树自动展开一级,右边树默认显示楼层,然后可以一个个展开 代码如下 <el-table :data="rel ...

  5. [51nod1325]两棵树的问题

    description 题面 solution 点分治+最小割. 点分必选的重心,再在树上dfs判交,转化为最大权闭合子图. 可以做\(k\)棵树的情况. code #include<iostr ...

  6. HDU 6315.Naive Operations-线段树(两棵树合并)(区间单点更新、区间最值、区间求和)+思维 (2018 Multi-University Training Contest 2 1007)

    6315.Naive Operations 题意很好理解,但是因为区间求和求的是向下取整的a[i]/b[i],所以直接分数更新区间是不对的,所以反过来直接当a[i]==b[i]的时候,线段树对应的位置 ...

  7. 判断两棵树是否相等 leecode

    很简单 提交代码 https://oj.leetcode.com/problems/same-tree/ iven two binary trees, write a function to chec ...

  8. 51nod 1551 集合交易 最大权闭合子图

    题意: 市场中有n个集合在卖.我们想买到满足以下要求的一些集合,所买到集合的个数要等于所有买到的集合合并后的元素的个数. 每个集合有相应的价格,要使买到的集合花费最小. 这里我们的集合有一个特点:对于 ...

  9. hdu-3015 Disharmony Trees---离散化+两个树状数组

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3015 题目大意: 有一些树,这些树的高度和位置给出.现在高度和位置都按从小到大排序,对应一个新的ra ...

随机推荐

  1. ZBrush中如何做不同图案的遮罩

    ZBrush®软件中不仅可以创建矩形遮罩还可以创建有图案的遮罩,且是非常简单有效的,那么究竟怎样做出神奇的效果,本文将为您详细讲解. 有关反转遮罩.清除遮罩的详细内容,请点击:ZBrush中如何反选遮 ...

  2. IPv6地址分配

  3. Java学习进阶—高级编程

    当你已经熟练的掌握了面向对象中的各种概念后,是否会对这些知识是如何使用的产生浓厚的兴趣?本课程主要针对于已经掌握了JAVA核心开发技术的读者准备,讲解了JAVA多线程.常用类库.IO编程.网络编程.类 ...

  4. Bzoj 2502: 清理雪道 有上下界网络流_最小流

    好长时间没有写网络流了,感觉好手生.对于本题,设一个源点 $s$ 和 $t$.1.由 $s$ 向每个点连一条没有下界,容量为无限大的边,表示以该点为起点.2.由每个点向 $t$ 连一条没有下界,容量为 ...

  5. 初见UDP_Client

    from socket import *ip_prot = ('192.168.55.1',8080)buffer_size = 1024udp_client = socket(AF_INET,SOC ...

  6. Pyhton学习——Day30

    # 内核态# 用户态# 操作系统的运行是在BOIS启动盘读取代码,从硬盘读取到内存中,被操作系统的内核中,一直存在在内存中# 计算机系统的三层结构:应用软件-->操作系统-->硬件# 一般 ...

  7. 使用iframe标签时如何通过jquery隐藏滚动条

    通过mouseover和mouseout事件来控制iframe的滚动条 代码如下:

  8. Codecademy网站安利 及 javaScript学习

    今天发现一个Code教学网站,号称可以利用零碎时间来学习些代码. codecademy (https://www.codecademy.com)

  9. thinkphp 多个字段的不同关系的查询条件实现 .

    tp的$map不同条件默认是 and ,如果要用or<><><><>如下 例如查询Stu表中年龄大于18,或者身高低于180cm的男性(1为男性),(例 ...

  10. Jquery-操作select下拉菜单

    jQuery获取Select选择的Text和Value: 1. var checkText=jQuery("#select_id").find("option:selec ...