正题

题目链接:https://www.luogu.com.cn/problem/AT4505


题目大意

给出\(n\)个点和\(n-1\)个点集\(U_i\),每个点集中选择两个点连边使得该图是一棵树。求方案。

\(n\in[1,10^5],\sum_{i=1}^{n-1} |U_i|\in[1,2*10^5]\)


解题思路

冬令营上讲的题目,现在来写。(而且好像我记得课上讲的做法是\(bitset\)的,还是时间久了我记岔了?)

第一眼看上去直觉像是\(hall\)定理但还是不会。

hall定理:\(2*n\)个点的二分图匹配,如果满足任意\(k\)个点都连接了不少于\(k\)个点的话,那么这张图就有完全匹配。

先套一下试试,发现满足条件的图对于它的每个子图\(S\)满足该子图是一个森林。

换句话说对于任意一个\(U\)的集合\(T\),\(G(T)\)表示选出的边连接的节点个数,那么一定有\(G(T)\geq |T|+1\)

回顾一下\(hall\)定理发现是不是很像。

可以先给每个点集选出一个各不同的点(也就是跑一次匹配),如果选不出来那么显然无解。

然后考虑另一个点的选择,从没有被选择的那个点入手,这个点可以选择任何一个包含它的点集连接出去,然后就从下一个点集开始,直到回溯回来选择下一个。如果最后能够遍历所有点就是合法的。

考虑一下正确性,如果它不能遍历所有点那么没有被遍历的点集\(T\)无论怎么连接外面,就一定有一个环不满足\(G(T)\geq |T|+1\)。如果它能遍历所有点,那么我们已经构造出一个方案,显然合法。

时间复杂度\(O(\sum_{i=1}^{n-1}|E|\sqrt n+n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=4e5+10,inf=1e9;
struct node{
int to,next,w;
}a[N*2];
int n,s,t,tot=1,cnt,ans;
int ls[N],p[N],b[N],dep[N],cur[N];
queue<int> q;bool v[N];
void addl(int x,int y,int w){
a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
return;
}
bool bfs(){
for(int i=1;i<=t;i++)
cur[i]=ls[i],dep[i]=0;
while(!q.empty())q.pop();q.push(s);
dep[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(dep[y]||!a[i].w)continue;
dep[y]=dep[x]+1;
if(y==t)return 1;
q.push(y);
}
}
return 0;
}
int dinic(int x,int flow){
if(x==t)return flow;
int rest=0,k;
for(int &i=cur[x];i;i=a[i].next){
int y=a[i].to;
if(dep[x]+1!=dep[y]||!a[i].w)continue;
rest+=(k=dinic(y,min(a[i].w,flow-rest)));
a[i].w-=k;a[i^1].w+=k;
if(rest==flow)return rest;
}
if(!rest)dep[x]=0;
return rest;
}
void dfs(int x){
cnt++;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(v[y])continue;
b[y]=x;v[y]=1;dfs(p[y]);
}
}
int main()
{
scanf("%d",&n);s=2*n;t=s+1;
for(int i=1;i<n;i++){
int m;scanf("%d",&m);
for(int j=1;j<=m;j++){
int x;scanf("%d",&x);
addl(x,i+n,1);
}
}
for(int i=1;i<=n;i++)addl(s,i,1);
for(int i=1;i<n;i++)addl(i+n,t,1);
while(bfs())
ans+=dinic(s,inf);
if(ans<n-1)return puts("-1")&0;
for(int x=n+1;x<s;x++)
for(int i=ls[x];i;i=a[i].next)
if(a[i].w){p[x]=a[i].to;break;}
v[s]=1;
for(int i=ls[s];i;i=a[i].next)
if(a[i].w)dfs(a[i].to);
if(cnt<n)return puts("-1")&0;
for(int x=n+1;x<s;x++)
printf("%d %d\n",p[x],b[x]);
return 0;
}

AT4505-[AGC029F]Construction of a tree【构造题,hall定理,网络流】的更多相关文章

  1. @atcoder - AGC029F@ Construction of a tree

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 N - 1 个 {1, 2, ..., N} 的子集,第 ...

  2. 【构造题 贪心】cf1041E. Tree Reconstruction

    比赛时候还是太慢了……要是能做快点就能上分了 Monocarp has drawn a tree (an undirected connected acyclic graph) and then ha ...

  3. HDU 5573 Binary Tree 构造

    Binary Tree 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5573 Description The Old Frog King lives ...

  4. AIM Tech Round 4 (Div. 1) C - Upgrading Tree 构造 + 树的重心

    C - Upgrading Tree 我发现我构造题好弱啊啊啊. 很明显能想到先找到重心, 然后我们的目标就是把所有点接到重心的儿子上,让重心的儿子子树变成菊花图, 这个先把重心到儿子的边连到 i , ...

  5. cf251.2.C (构造题的技巧)

    C. Devu and Partitioning of the Array time limit per test 1 second memory limit per test 256 megabyt ...

  6. hdu4671 Backup Plan ——构造题

    link:http://acm.hdu.edu.cn/showproblem.php?pid=4671 其实是不难的那种构造题,先排第一列,第二列从后往前选. #include <iostrea ...

  7. Educational Codeforces Round 7 D. Optimal Number Permutation 构造题

    D. Optimal Number Permutation 题目连接: http://www.codeforces.com/contest/622/problem/D Description You ...

  8. Codeforces 482 - Diverse Permutation 构造题

    这是一道蛮基础的构造题. - k         +(k - 1)      -(k - 2) 1 + k ,    1 ,         k ,             2,    ....... ...

  9. BZOJ 3097: Hash Killer I【构造题,思维题】

    3097: Hash Killer I Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 963  Solved: 36 ...

随机推荐

  1. [转]C# 互操作性入门系列(二):使用平台调用调用Win32 函数

    传送门 C#互操作系列文章: C# 互操作性入门系列(一):C#中互操作性介绍 C# 互操作性入门系列(二):使用平台调用调用Win32 函数 C# 互操作性入门系列(三):平台调用中的数据封送处理 ...

  2. Java 数组结构

    数组是最常见的一种数据结构,是相同类型的.用一个标识符封装到一起的基本类型数据序列或对象序列.可以用一个统一的数组名和下标来唯一确定数组中的元素.实质上数组是一个简单的线性序列,因此数组访问起来很快. ...

  3. docker下gitlab(redis)安装配置使用(完整版)

    ps:如果是云主机,需添加安全组开放相应端口(关联相应实例),防火墙开放端口或直接关闭 https://www.jianshu.com/p/080a962c35b6 将其中external_url换为 ...

  4. 使用dom4j工具:xml总结

    1.IO流:BufferedReader字符流readLine();截取 不可行!!!2.XML解析:dom4j查:标签:element("name")elements(" ...

  5. 刷题-力扣-113. 路径总和 II

    113. 路径总和 II 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/path-sum-ii 著作权归领扣网络所有.商业转载请联系 ...

  6. redis集群访问,重启,关闭,带密码访问集群

    安装ruby后查找如下文件  vi  进去后编辑 此处编写自己的密码,重启后便可带密码访问集群 随便选择一个节点输入如下指令查看集群信息 正常关闭redis命令如下: 重启redis集群再次以相同的命 ...

  7. GUI容器之布局管理器

    布局管理器 布局管理器:frame.setLayout(); 默认值为new flowLayout() 流式布局 frame.setLayout(new FlowLayout(FlowLayout.R ...

  8. 移动端ios上下滑动翻页事件失效

    移动端开发过程中,在添加上下滑动事件时候,引入了最常用的移动端库zepto.js及其touch模块,有一种现象,安卓的手机没有问题,上下滑动翻页很正常 :但是到了ios上面,好啊,上下滑动会出现弹性滚 ...

  9. 查看所有日志命令:journalctl

    journalctl命令作用:实时查看所有日志(内核日志和应用日志) 语法格式: journalctl [参数] 常用参数:-k 查看内核日志-b 查看系统本次启动的日志-u 查看指定服务的日志-n ...

  10. elementUI+nodeJS环境搭建

    一. ElementUI简介 我们学习VUE,知道它的核心思想式组件和数据驱动,但是每一个组件都需要自己编写模板,样式,添加事件,数据等是非常麻烦的, 所以饿了吗推出了基于VUE2.0的组件库,它的名 ...