[atAGC029F]Construction of a tree
构造一张二分图,左边是$n$个点,右边是$n-1$个集合,按照点属于集合连边
定义一组匹配的意义,即说明该点的父亲在该集合中选择
利用dinic求出二分图的最大匹配,若不为$n-1$则无解,否则考虑如何去构造一组解:
考虑左边剩下的未参与匹配的点$x$,将其作为根,并将所有含有$x$的集合所匹配的点都作为$x$的儿子,重复此过程(对于其他点,要加上一个“未被选择过”)
事实上,这个过程可以看作从源点出发在残余网络上的一棵bfs树,合法当且仅当能bfs到所有点
(能从$x$走到对应集合当且仅当其匹配的不是该集合,能从一个集合走到$y$当且仅当$y$匹配了该集合,同时$y$一定不会去选择其所匹配的集合中的点,因为一定被其父亲选择完毕)
下面,我们来证明若某一种匹配方式不能做到,则其余都不行:
由于根是任意的,换言之这个点作为根如果不行,其余点也都不行,因此确定了根
考虑调整匹配方案,一定可以通过若干次对一个序列的循环(通过将调整建为一张图可以证明)
若轮换前这一个集合中存在一个点能被搜到,按照轮换的顺序其余点都能被搜到,因此轮换前所有点都不能被搜到,即是一个内部的交换,没有意义
总复杂度为$o(n\sqrt{n})$,可以通过

1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 100005
4 #define oo 0x3f3f3f3f
5 struct ji{
6 int nex,to,len;
7 }edge[N<<3];
8 queue<int>q;
9 pair<int,int>ans[N];
10 int E,n,x,y,tot,head[N<<1],work[N<<1],d[N<<1];
11 void add(int x,int y,int z){
12 edge[E].nex=head[x];
13 edge[E].to=y;
14 edge[E].len=z;
15 head[x]=E++;
16 if (E&1)add(y,x,0);
17 }
18 bool bfs(){
19 memset(d,oo,sizeof(d));
20 d[0]=0;
21 q.push(0);
22 while (!q.empty()){
23 int k=q.front();
24 q.pop();
25 for(int i=head[k];i!=-1;i=edge[i].nex)
26 if ((edge[i].len)&&(d[edge[i].to]==oo)){
27 d[edge[i].to]=d[k]+1;
28 q.push(edge[i].to);
29 }
30 }
31 return d[2*n]<oo;
32 }
33 int dfs(int k,int s){
34 if (k==2*n)return s;
35 for(int &i=work[k];i!=-1;i=edge[i].nex)
36 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){
37 int p=dfs(edge[i].to,min(s,edge[i].len));
38 if (p){
39 edge[i].len-=p;
40 edge[i^1].len+=p;
41 return p;
42 }
43 }
44 return 0;
45 }
46 int dinic(){
47 int k,ans=0;
48 while (bfs()){
49 memcpy(work,head,sizeof(work));
50 while (k=dfs(0,oo))ans+=k;
51 }
52 return ans;
53 }
54 void bfs_build(){
55 memset(d,0,sizeof(d));
56 for(int i=head[0];i!=-1;i=edge[i].nex)
57 if (edge[i].len){
58 q.push(edge[i].to);
59 d[edge[i].to]=edge[i].to;
60 }
61 while (!q.empty()){
62 int k=q.front();
63 q.pop();
64 for(int i=head[k];i!=-1;i=edge[i].nex)
65 if ((edge[i].to)&&(edge[i].len)&&(!d[edge[i].to])){
66 if (edge[i].to>n)d[edge[i].to]=d[k];
67 else{
68 tot++;
69 ans[k-n]=make_pair(d[k],edge[i].to);
70 d[edge[i].to]=edge[i].to;
71 }
72 q.push(edge[i].to);
73 }
74 }
75 }
76 int main(){
77 scanf("%d",&n);
78 memset(head,-1,sizeof(head));
79 for(int i=1;i<=n;i++)add(0,i,1);
80 for(int i=1;i<n;i++){
81 scanf("%d",&x);
82 add(i+n,2*n,1);
83 for(int j=1;j<=x;j++){
84 scanf("%d",&y);
85 add(y,i+n,1);
86 }
87 }
88 if (dinic()<n-1){
89 printf("-1");
90 return 0;
91 }
92 bfs_build();
93 if (tot!=n-1)printf("-1");
94 else{
95 for(int i=1;i<n;i++)
96 printf("%d %d\n",ans[i].first,ans[i].second);
97 }
98 }
[atAGC029F]Construction of a tree的更多相关文章
- @atcoder - AGC029F@ Construction of a tree
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 N - 1 个 {1, 2, ..., N} 的子集,第 ...
- AT4505-[AGC029F]Construction of a tree【构造题,hall定理,网络流】
正题 题目链接:https://www.luogu.com.cn/problem/AT4505 题目大意 给出\(n\)个点和\(n-1\)个点集\(U_i\),每个点集中选择两个点连边使得该图是一棵 ...
- phylogeny analysis
Multiple Alignment: MUSCLE ProbCons T-Coffee ClustalW Alignment curation: Gblocks Remove positions w ...
- 【AtCoder】AGC029(A-E)
A - Irreversible operation 题解 把每个B后面的W个数累加起来即可 代码 #include <bits/stdc++.h> #define fi first #d ...
- JS进阶 - 浏览器工作原理
一.浏览器的结构 浏览器的主要组件为: 用户界面 - 包括地址栏.前进/后退按钮.书签菜单等.除了浏览器主窗口(显示页面),其他部分都属于用户界面. 浏览器引擎 - 在用户界面和渲染引擎之间传送指令. ...
- Bounding Volume Hierarchy BVH in OpenCASCADE
Bounding Volume Hierarchy BVH in OpenCASCADE eryar@163.com Abstract. Bounding Volume Hierarchy(BVH) ...
- WC2021 题目清单
Day2 上午 <IOI题型与趣题分析> 来源 题目 完成情况 备注 IOI2002 Day1T1 Frog 已完成 IOI2002 Day1T2 Utopia IOI2002 Day1T ...
- 数据结构 - Codeforces Round #353 (Div. 2) D. Tree Construction
Tree Construction Problem's Link ------------------------------------------------------------------- ...
- STL---Codeforces675D Tree Construction(二叉树节点的父亲节点)
Description During the programming classes Vasya was assigned a difficult problem. However, he doesn ...
随机推荐
- 11.4.5 LVS负载均衡常见工作模式总结以及ipvsadm
NAT TUN DR RS any Tunneling Non-arp device RS network private LAN/WAN LAN RS number low(10-20) Hig ...
- 调试器地址出现大小端紊乱,引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突。
今天在编写一系列新增需求代码后,开始调试代码 发现上个版本正常可运行的代码出现了:引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突. 上个版本数代码 ...
- 【分享】 一款自用的Anki卡片模板:黄子涵单词卡片 v1
[分享] 一款自用的Anki卡片模板:黄子涵单词卡片 v1 说明 第一代的功能 主要有两部分组成:英文和含义,目前主要是为自己记忆Web前端一些常用的单词而服务 有美美哒背景图,本来想修改为随机背景图 ...
- 使用CSS选择器(第二部分)
伪类跟伪元素一样,并不是直接针对文档元素的,而是为你基于某些共同特征选择元素提供方便. 使用结构性伪类选择器 使用结构性伪类选择器能够根据元素在文档中的位置选择元素.这类选择器都有一个冒号字符前缀(: ...
- 详解build-gradle文件
目录 gradle 两个build.gradle文件 最外层目录下的build.gradle文件 jcenter dependencies闭包 app目录下的build.gradle文件 com.an ...
- Netty 了解
1.1 Netty 是什么? Netty is an asynchronous event-driven network application framework for rapid develop ...
- Google Style Guides
Google Style Guides Google Style Guides Google 开源项目风格指南 (zh-google-styleguide.readthedocs.io)
- sql常用的统计公式
hivesql中max,min函数不能作用于多列,因此在有上下门限区间限制时多用公式直接计算. max(x,y)=(x+y+ABS(x-y))/2 min(x,y)=(x+y-ABS(x-y))/2 ...
- javascript-jquery介绍
jquery优势 1.轻量级 2.强大的选择器 3.出色的DOM封装 4.可靠的事件处理机制 5.完善的Ajax 6.不污染顶级变量 7.出色的浏览器兼容 8.链式操作方式 9.隐式迭代 10.行为层 ...
- Spring Security Jwt Token 自动刷新
token的自动刷新 一.功能需求 二.功能分析 1.token 的生成 2.token 的自动延长 3.系统资源的保护 4.用户如何传递 token 三.实现思路 1.生成 token 和 refr ...