[jzoj 4528] [GDOI2019模拟2019.3.26] 要换换名字 (最大权闭合子图)
题目链接:
https://jzoj.net/senior/#contest/show/2683/0
题目:
题解:
不妨枚举一个点,让两颗树都以这个点为根,求联通块要么点数为$0$,要么包括根(即联通块必须从根开始)
考虑一个不是根的点$x$,若$x$在联通块以内,要保证联通块的连通性,那么从$x$的父亲要在联通块以内
这种一个点选了就必须要选另一个点的问题是典型的最大权闭合子图模型
做法如下
设$s$为源点,$t$为汇点。
使$s$连向所有的正权点(非负权点),边权为点权
使所有非负权点(负权点)连向$t$,边权为点权的绝对值
若需要选$y$就要选$x$,连一条由$x$到$y$的边,边权是$∞$(其实这个地方我一直有疑惑,有的认为是连从$x$到$y$的边,如果有读者知道真相麻烦告诉我)
最大点权和=正权点和-最小割
证明:
我们知道一个割会把图分成两个部分,一部分是$S$能走到的,另一部分是能走到$T$的。
我们设这两个集合为$A$,$B$。
$A0$,$B0$分别表示$A$,$B$中原来点权是负数的点集, $A1$,$B1$分别表示$A$,$B$中点权原来是正数的点集。
由于中间的边是$∞$的,割的一定是和$S$,$T$相连的边,这个叫简单割。
所以割的大小 $= |A0| +B1$
$A,B$一定是最大权闭合子图
$A$的点权和 $= A1 - |A0|$
$A$的点权和+割的大小$=A1 + B1 = $全图中的正权点和
这是一个定值, 要使$A$的点权和最大, 就要使割最小,就是最小割,
至此得证。
代码:
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std; const int N=+;
const int inf=1e9+;
int n,tot1,tot2,cnt;
int a[N],h1[N],h2[N],head[N],dep[N],nowhead[N];
struct EDGE
{
int to,nxt;
}e1[N<<],e2[N<<];
struct node
{
int to,nxt;
int flow;
}edge[N<<];
inline int read()
{
char ch=getchar();int s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
void link(int u,int v,int w)
{
edge[++cnt]=(node){v,head[u],w};head[u]=cnt;
edge[++cnt]=(node){u,head[v],};head[v]=cnt;
}
void add1(int u,int v)
{
e1[++tot1]=(EDGE){v,h1[u]};
h1[u]=tot1;
}
void add2(int u,int v)
{
e2[++tot2]=(EDGE){v,h2[u]};
h2[u]=tot2;
}
void init()
{
cnt=;
memset(head,-,sizeof(head));
}
void dfs1(int x,int pre)
{
if (pre) link(x,pre,inf);
for (int i=h1[x];i;i=e1[i].nxt)
{
int y=e1[i].to;
if (y==pre) continue;
dfs1(y,x);
}
}
void dfs2(int x,int pre)
{
if (pre) link(x,pre,inf);
for (int i=h2[x];i;i=e2[i].nxt)
{
int y=e2[i].to;
if (y==pre) continue;
dfs2(y,x);
}
}
int S,T;
queue <int> q;
int bfs()
{
memset(dep,,sizeof(dep));
while (!q.empty()) q.pop();
dep[S]=;
q.push(S);
while (!q.empty())
{
int k=q.front();q.pop();
for (int i=head[k];i!=-;i=edge[i].nxt)
if (edge[i].flow&&!dep[edge[i].to])
{
dep[edge[i].to]=dep[k]+;
q.push(edge[i].to);
}
}
return dep[T];
}
int dfs(int x,int a)
{
if (x==T||!a) return a;
int flow=,f;
for (int &i=nowhead[x];i!=-;i=edge[i].nxt)
if (dep[x]+==dep[edge[i].to]&&(f=dfs(edge[i].to,min(a,edge[i].flow)))>)
{
edge[i].flow-=f;
edge[i^].flow+=f;
flow+=f;
a-=f;
if (a==) break;
}
return flow;
}
int dinic()
{
int ans=;
while (bfs())
{
copy(head,head+n+,nowhead);//这行优化重要无比
ans+=dfs(S,inf);
}
return ans;
}
int main()
{
//freopen("theory.in","r",stdin);
int W=read();
while (W--)
{
tot1=;tot2=;
int sum=;
n=read();
S=n+,T=n+;
for (int i=;i<=n;i++)
{
h1[i]=;h2[i]=;
a[i]=read();
if (a[i]>) sum+=a[i];
}
for (int i=;i<n;i++)
{
int u=read(),v=read();
add1(u,v);add1(v,u);
}
for (int i=;i<n;i++)
{
int u=read(),v=read();
add2(u,v);add2(v,u);
}
int res=;
for (int i=;i<=n;i++)
{
init();
dfs1(i,);dfs2(i,);
for (int j=;j<=n;j++) if (a[j]>=) link(S,j,a[j]);else link(j,T,-a[j]);
res=max(res,sum-dinic());
}
printf("%d\n",res);
}
return ;
}
[jzoj 4528] [GDOI2019模拟2019.3.26] 要换换名字 (最大权闭合子图)的更多相关文章
- [jzoj 6086] [GDOI2019模拟2019.3.26] 动态半平面交 解题报告 (set+线段树)
题目链接: https://jzoj.net/senior/#main/show/6086 题目: 题解: 一群数字的最小公倍数就是对它们质因数集合中的每个质因数的指数取$max$然后相乘 这样的子树 ...
- [jzoj 6087] [GDOI2019模拟2019.3.26] 获取名额 解题报告 (泰勒展开+RMQ+精度)
题目链接: https://jzoj.net/senior/#main/show/6087 题目: 题解: 只需要统计$\prod_{i=l}^r (1-\frac{a_i}{x})$ =$exp(\ ...
- [jzoj 6092] [GDOI2019模拟2019.3.30] 附耳而至 解题报告 (平面图转对偶图+最小割)
题目链接: https://jzoj.net/senior/#main/show/6092 题目: 知识点--平面图转对偶图 在求最小割的时候,我们可以把平面图转为对偶图,用最短路来求最小割,这样会比 ...
- [jzoj 6101] [GDOI2019模拟2019.4.2] Path 解题报告 (期望)
题目链接: https://jzoj.net/senior/#main/show/6101 题目: 题解: 设$f_i$表示从节点$i$到节点$n$的期望时间,$f_n=0$ 最优策略就是如果从$i, ...
- [jzoj 6093] [GDOI2019模拟2019.3.30] 星辰大海 解题报告 (半平面交)
题目链接: https://jzoj.net/senior/#contest/show/2686/2 题目: 题解: 说实话这题调试差不多花了我十小时,不过总算借着这道题大概了解了计算几何的基础知识 ...
- [jzoj 6080] [GDOI2019模拟2019.3.23] IOer 解题报告 (数学构造)
题目链接: https://jzoj.net/senior/#main/show/6080 题目: 题意: 给定$n,m,u,v$ 设$t_i=ui+v$ 求$\sum_{k_1+k_2+...+k_ ...
- [jzoj 6084] [GDOI2019模拟2019.3.25] 礼物 [luogu 4916] 魔力环 解题报告(莫比乌斯反演+生成函数)
题目链接: https://jzoj.net/senior/#main/show/6084 https://www.luogu.org/problemnew/show/P4916 题目: 题解: 注: ...
- jzoj6101. 【GDOI2019模拟2019.4.2】Path
题目链接:https://jzoj.net/senior/#main/show/6101 记\(f_i\)为从\(i\)号点走到\(n\)号点所花天数的期望 那么根据\(m\)条边等可能的出现一条和一 ...
- jzoj6099. 【GDOI2019模拟2019.4.1】Dist
题目链接:https://jzoj.net/senior/#main/show/6099 考虑直接统计某个点到其它所有点的距离和 我们先把整个团当成一个点建图,处理出任意两个团之间的距离\(dis(i ...
随机推荐
- linux服务器卸载本机默认安装的jdk
1. 查看系统安装的版本情况: rpm -qa | grep jdk rpm -qa | grep gcj 2. 查看并删除 [root@iZ2zeedm3x12d8xb4g15a ...
- POJ 2346 DP or打表
这题 不算重复的数.. 就变成水题了. 思路: 1.打表 2.DP 打表的: // by SiriusRen #include <cstdio> using namespace std; ...
- javascript中手风琴特效
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- Android Handler学习笔记
已经习惯了挖坑不填,继续任性一下,周一到周五继续挖坑,每周六周日负责填坑. 1.从Android UI线程谈起 出于性能考虑,Android 中的UI操作并不是线程安全的,所以Android中规定只能 ...
- Javescript 面向对象编程 — 封装
生成实例对象的原始模式 <script type="text/javascript"> var Cat={ name:'波斯猫', color:'White' } al ...
- 【WPF】这可能是全网最全的拖拽实现方法的总结
原文地址 https://www.cnblogs.com/younShieh/p/10811456.html 前文 本文只对笔者学习掌握的一般的拖动问题的实现方法进行整理和讨论,包括窗口.控件等内容的 ...
- sklearn学习4----预处理(1)标准化
一.[标准化]scale: 1.导入模块 from sklearn.preprocessing import scaler 2.作用:直接将给定数据进行标准化 3.使用代码 X_scaled=sca ...
- How to debug systemd step by step
docker run -ti --name systemd --net host --privileged reg.docker.xxxxxxxx:latest /usr/lib/systemd/sy ...
- Vue -- 只弹一次的弹框
核心代码是 getCookie()部分,控制弹框的显示隐藏则在 created()中. <template> <div v-if="isShow"> < ...
- 火狐浏览器安装接口测试工具RESTClient方法