51 NOD 1325 两棵树的问题
Discription

对于 100% 的数据, N<=50.
solution:
发现N比较小,所以我们可以花O(N^2)的代价枚举两颗树的联通块的LCA分别是哪个点,然后现在问题就变成了:选一个点必须要选它在两个树上的祖先,问如何选点可以使收益最大。
这是一个裸的 最大权闭合子图 问题, 节点连S表示选,连T表示不选,如果选x必须选y那么就连<x,y,inf>,最后的答案就是 所有正的a的和 - 这个图的最小割。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int maxn=55;
vector<int> g[maxn];
struct lines{
int to,flow,cap;
}l[maxn*maxn];
int t=-1,S,T,d[maxn],cur[maxn];
bool v[maxn]; inline void add(int from,int to,int cap){
l[++t]=(lines){to,0,cap},g[from].pb(t);
l[++t]=(lines){from,0,0},g[to].pb(t);
} inline bool BFS(){
memset(v,0,sizeof(v));
queue<int> q;
q.push(S),v[S]=1,d[S]=0;
int x; lines e; while(!q.empty()){
x=q.front(),q.pop();
for(int i=g[x].size()-1;i>=0;i--){
e=l[g[x][i]];
if(e.flow<e.cap&&!v[e.to]){
v[e.to]=1,d[e.to]=d[x]+1;
q.push(e.to);
}
}
} return v[T];
} int dfs(int x,int A){
if(x==T||!A) return A;
int flow=0,f,sz=g[x].size();
for(int &i=cur[x];i<sz;i++){
lines &e=l[g[x][i]];
if(d[x]==d[e.to]-1&&(f=dfs(e.to,min(A,e.cap-e.flow)))){
A-=f,flow+=f;
e.flow+=f,l[g[x][i]^1].flow-=f;
if(!A) break;
}
} return flow;
} inline int max_flow(){
int an=0;
while(BFS()){
memset(cur,0,sizeof(cur));
an+=dfs(S,1<<30);
}
return an;
} vector<int> son[maxn];
int hd[maxn],ne[maxn*2];
int n,a[maxn],TO[maxn*2];
int F[2][maxn],NOW,ans; void dfs1(int x,int fa){
F[0][x]=fa;
for(int i=son[x].size()-1,O;i>=0;i--){
O=son[x][i];
if(O==fa) continue;
dfs1(O,x);
}
} void dfs2(int x,int fa){
F[1][x]=fa;
for(int i=hd[x];i;i=ne[i]) if(TO[i]!=fa)
dfs2(TO[i],x);
} inline void build(){
t=-1;
for(int i=0;i<=T;i++) g[i].clear();
for(int i=1;i<=n;i++){
if(F[0][i]) add(i,F[0][i],1<<30);
if(F[1][i]) add(i,F[1][i],1<<30);
if(a[i]>0) add(S,i,a[i]);
else add(i,T,-a[i]);
}
} int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
NOW+=max(0,a[i]);
}
int uu,vv;
for(int i=1;i<n;i++){
scanf("%d%d",&uu,&vv),uu++,vv++;
son[uu].pb(vv),son[vv].pb(uu);
}
for(int i=1;i<n;i++){
scanf("%d%d",&uu,&vv),uu++,vv++;
TO[i]=vv,ne[i]=hd[uu],hd[uu]=i;
TO[i+n]=uu,ne[i+n]=hd[vv],hd[vv]=i+n;
} S=0,T=n+1;
for(int i=1;i<=n;i++){
dfs1(i,0);
for(int j=1;j<=n;j++){
dfs2(i,0);
build();
ans=max(ans,NOW-max_flow());
}
} printf("%d\n",ans);
return 0;
}
51 NOD 1325 两棵树的问题的更多相关文章
- 51nod 1325 两棵树的问题(最大权闭合子图)
首先如果点权全都为正,就可以直接选所有的点. 活在梦里.. 考虑枚举一个点\(i\),作为我们选择的集合中的一个点. 然后我们把另一个点\(j\)选入集合的时候必须把两棵树中\(i\)和\(j\)路径 ...
- LeetCode——Same Tree(判断两棵树是否相同)
问题: Given two binary trees, write a function to check if they are equal or not. Two binary trees are ...
- WPF的两棵树与绑定
原文:WPF的两棵树与绑定 先建立测试基类 public class VisualPanel : FrameworkElement { protected VisualCollection Chi ...
- element ui改写实现两棵树
使用element ui组件库实现一个table的两棵树的效果 效果如下,左边树自动展开一级,右边树默认显示楼层,然后可以一个个展开 代码如下 <el-table :data="rel ...
- [51nod1325]两棵树的问题
description 题面 solution 点分治+最小割. 点分必选的重心,再在树上dfs判交,转化为最大权闭合子图. 可以做\(k\)棵树的情况. code #include<iostr ...
- HDU 6315.Naive Operations-线段树(两棵树合并)(区间单点更新、区间最值、区间求和)+思维 (2018 Multi-University Training Contest 2 1007)
6315.Naive Operations 题意很好理解,但是因为区间求和求的是向下取整的a[i]/b[i],所以直接分数更新区间是不对的,所以反过来直接当a[i]==b[i]的时候,线段树对应的位置 ...
- 判断两棵树是否相等 leecode
很简单 提交代码 https://oj.leetcode.com/problems/same-tree/ iven two binary trees, write a function to chec ...
- 51 nod 1681 公共祖先 (主席树+dfs序)
1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...
- hdu-3015 Disharmony Trees---离散化+两个树状数组
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3015 题目大意: 有一些树,这些树的高度和位置给出.现在高度和位置都按从小到大排序,对应一个新的ra ...
随机推荐
- 简单的Redis数据迁移
dump迁移 1.安装redis-dump工具 sudo apt-get install ruby rubygems ruby-devel -y gem sources --add http://ge ...
- (60)zabbix网络发现介绍Network Discovery
网络发现简介 网络发现有什么用?网络发现怎么配置? 我们带着这两个问题开始我们的网络发现之旅. 比如小明有100台服务器,不想一台台主机去添加,能不能让zabbix自动添加主机呢,当然可以,网络发现便 ...
- mysql:explain分析sql
对于执行较慢的sql,可以使用explain命令查看这些sql的执行计划.查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看 mysql> explain ...
- TB平台搭建之三
有简单到复杂,可以简单的决不复杂化,事情从可控开始,即使再好的技术如果不可控最好不要用否则以后的debug可能比较麻烦. 无论是搭建平台还是写复杂的case都是尽量从简单开始,不要上来复杂,否则deb ...
- perl学习之:匹配修饰符/s /m
m 是将字符串作为多行处理,s是将字符串作为单行处理,如果是s在字符串中出现的\n就相当于普通字符. 6.6. Matching Within Multiple Lines6.6.1. Problem ...
- Handler处理器和自定义Opener
Handler处理器 和 自定义Opener opener是 urllib2.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的opener(也就是模块帮我们构 ...
- linux中软件包管理
一.流行的软件包管理有两种: Debian Linux的Deb软件包和 Redhat Linux的Rpm软件包, Debian Linux首先提出将应用程序的二进制文件.配置文档.man/info帮助 ...
- go的相关用法
1. have gone to和have been to的区别 have gone to和have been to的区别如下: 1.have gone to,第三人称时用 has gone to ha ...
- x86保护模式-六 控制转移
控制转移可以分为两大类 :同一任务内的控制转移 和 任务间的控制转移(任务切换) 同一个任务内的控制转移可以分为段内转移 .特权级不变的段间转移和特权级改变的段间转移 段内转移与实模式相同 ...
- NYOJ 722 数独
数独 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 数独是一种运用纸.笔进行演算的逻辑游戏.玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一 ...