[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=600+15; const int inf=1e9+7; 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<<1],e2[N<<1]; struct node {int to,nxt;int flow; }edge[N<<2]; inline int read() {char ch=getchar();int s=0,f=1;while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';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],0};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=1;memset(head,-1,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,0,sizeof(dep));while (!q.empty()) q.pop(); dep[S]=1;q.push(S);while (!q.empty()){int k=q.front();q.pop();for (int i=head[k];i!=-1;i=edge[i].nxt)if (edge[i].flow&&!dep[edge[i].to]){dep[edge[i].to]=dep[k]+1;q.push(edge[i].to);}}return dep[T]; } int dfs(int x,int a) {if (x==T||!a) return a;int flow=0,f;for (int &i=nowhead[x];i!=-1;i=edge[i].nxt)if (dep[x]+1==dep[edge[i].to]&&(f=dfs(edge[i].to,min(a,edge[i].flow)))>0){edge[i].flow-=f;edge[i^1].flow+=f;flow+=f;a-=f;if (a==0) break;}return flow; } int dinic() {int ans=0;while (bfs()){ copy(head,head+n+3,nowhead);//这行优化重要无比 ans+=dfs(S,inf);} return ans; } int main() {//freopen("theory.in","r",stdin);int W=read();while (W--){tot1=0;tot2=0;int sum=0;n=read();S=n+1,T=n+2;for (int i=1;i<=n;i++) {h1[i]=0;h2[i]=0;a[i]=read();if (a[i]>0) sum+=a[i];}for (int i=1;i<n;i++){int u=read(),v=read();add1(u,v);add1(v,u);}for (int i=1;i<n;i++){int u=read(),v=read();add2(u,v);add2(v,u);}int res=0;for (int i=1;i<=n;i++){init();dfs1(i,0);dfs2(i,0);for (int j=1;j<=n;j++) if (a[j]>=0) link(S,j,a[j]);else link(j,T,-a[j]);res=max(res,sum-dinic());}printf("%d\n",res);}return 0; }
转载于:https://www.cnblogs.com/xxzh/p/10604083.html
[jzoj 4528] [GDOI2019模拟2019.3.26] 要换换名字 (最大权闭合子图)相关推荐
- [jzoj 6093] [GDOI2019模拟2019.3.30] 星辰大海 解题报告 (半平面交)
题目链接: https://jzoj.net/senior/#contest/show/2686/2 题目: 题解: 说实话这题调试差不多花了我十小时,不过总算借着这道题大概了解了计算几何的基础知识 ...
- gmoj 6087. 【GDOI2019模拟2019.3.26】获取名额 题解
题目 https://gmoj.net/senior/#main/show/6087 题解 发现 ans=1−∏i=lr(1−aix)ans=1-\prod_{i=l}^r \left(1-\frac ...
- JZOJ 6030. 【GDOI2019模拟2019.2.25】白白的
Description Input Output Sample Input 4 3 6 0 10 1 1 2 1 0 1 2 Sample Output 1 1 0 Data Constraint S ...
- 【JZOJ 6079】【GDOI2019模拟2019.3.23】染色问题
Description m≤n+5,k,n≤105m\leq n+5,k,n\leq10^5m≤n+5,k,n≤105 Solution 1 这个图只有5条返祖边所以才能做, 先把所有有返祖边的点拿出 ...
- [JZOJ6075]【GDOI2019模拟2019.3.20】桥【DP】【线段树】
Description N,M<=100000,S,T<=1e9 Solution 首先可以感受一下,我们把街道看成一行,那么只有给出的2n个点的纵坐标是有用的,于是我们可以将坐标离散化至 ...
- [JZOJ6093]【GDOI2019模拟2019.3.30】星辰大海【计算几何】【半平面交】
Description 给出平面上n个点,其中1号点是可以移动的,但是移动的范围不能改变任意三个点所成的角的状态([0,π),[π,π],(π,2π][0,\pi),[\pi,\pi],(\pi,2\ ...
- 训练日志 2019.1.26
上午补了道 2-sat 的题,这类问题还是不太熟练,不是很能准确的找到条件 下午打比赛,立的 flag 成功崩了...数组没开小但把精度爆了..+= 把 + 忘了...一道巨水的题把输入看错了...大 ...
- 18天精读掌握《费曼物理学讲义卷一》 第10天 2019/6/26
18天精读掌握<费曼物理学讲义卷一> 第10天 2019/6/26 1. 18日掌握<费曼物理学讲义>卷一计划概览 2. 今日学习成果 3. 今日时间表 4.Atimelogg ...
- 2019.10.26
2019.10.26 void Level::keyPressEvent(QKeyEvent *event){switch(event->key()){case Qt::Key_A:goingL ...
- 棒棒糖-小学数学出题机v1.4.2【更新2019/12/26】
[推荐]2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 今年儿子刚上一年级,现在每天要做口算题,每次都要打印100题随机题目让他做,网上找了很多出题器,不是操作太繁琐 ...
最新文章
- 创建windows窗口并且获得窗口句柄
- RabbitMQ+PHP 教程六(RPC)
- bert之我见 - positional encoding
- python中安装pip_Python中如何安装pip-百度经验
- Kindle 2 初探
- java 电子签章 开源_java操作pdf制作电子签章 - CSDN博客
- 服务器系统root密码忘记,云服务器 忘记root密码忘记了
- 【笔试面试】携程笔试面试注意事项
- dell笔记本外接显示器_戴尔笔记本怎么连接外接显示器?
- Poj1704:staircase nim【博弈】
- (c语言)字符串的大小写字母转化函数
- 如何快速做一个HTML5移动播放器
- 基于python pygame实现的雨点动画
- Java学习第七项--类和对象
- eclipse怎么搜索关键字? eclipse查找关键字的技巧
- Postfix+dovecot邮件
- scrapy+redis+mongodb爬取苏宁商城图书价格
- pytorch,torch,torchvision的gpu版本安装避坑
- 管理学之人际关系理论
- 串口公头(九针)母头(九孔)对应接口(转)