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

活在梦里。。

考虑枚举一个点\(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. ZBrush中设置背面遮罩的两种方法

    背面遮罩是ZBrush软件实时遮罩的一种,它的出现能够解决我们在模型雕刻时的一些问题.我们在 ZBrush®中雕刻一个比较薄的物体时,经常会不经意的雕刻到背面的物体.那么遇到此类状况该如何设置ZBru ...

  3. Aspose.Cells基础使用方法整理

    Aspose.Cells 插件,将web端数据以excel形式导出到客户端. 相关文档: https://blog.csdn.net/djk8888/article/details/53065416 ...

  4. 关于mysql无法添加中文数据的问题以及解决方案(转载)

    今天弄了一天的mysql数据库,就是被一个mysql数据库乱码的问题给缠住了.现在记录一下这个问题,虽然这个问题不是什么太大的事情,但还是记录一下. 问题是这样的: 1.先在mysql的安装文件当中, ...

  5. [置顶] 智能家居开源项目 The open Home Automation Bus (openHAB)

    ================================================================================ 2014-05-19 论文的事情太多, ...

  6. 使用命令:ssh-add 时,出现 “Could not open a connection to your authentication agent.”

    为 GitHub 账号设置 SSH Key时, 使用命令:ssh-add,出现“Could not open a connection to your authentication agent”,解决 ...

  7. BZOJ 5020 [THUWC2017]Drown in the math ocean (LCT+求导)

    题目大意: 太长了略 洛谷题面传送门 嗯,数学题 感觉考试要是出这种题我就死翘翘了[逃 不用想都知道要$LCT$维护断边连边,但询问该如何处理呢 利用题目给出的公式 $f(x)=\sum_{i=0}^ ...

  8. libvirtd.service

    [root@kvm-server ~]# systemctl status libvirtd.service ● libvirtd.service - Virtualization daemon Lo ...

  9. [宏]_IO, _IOR, _IOW, _IOWR 宏的用法与解析

    在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值.cmd除了可区别数字外,还包含有助于处理的几种相应信息. cmd的大小为 32位,共分 4 个 ...

  10. CMDB设计

    CMDB(资产管理数据库) CMDB是所有运维工具的数据基础 CMDB包含的内容 用户管理,记录测试,开发,运维人员的用户表 业务线管理,需要记录业务的详情 项目管理,指定此项目用属于哪条业务线,以及 ...