Codeforces Round #738 (Div. 2) D2题解
D2. Mocha and Diana (Hard Version)
至于D1,由于范围是1000,我们直接枚举所有的边,看看能不能加上去就行,复杂度是\(O(n^2logn)\).至于\(n\)到了\(1e5\),就要重新考虑解法。
考虑到树的边数是\(n-1\)。也就是说我们枚举的大多数边都是无效的,这个时候就要考虑我们能不能只连有效的边,对于两个连通块而言,显然在这两个连通块之间我们只需要连一条边就可以了。还有一般这种两个图的题,一般都是在一个图中操作,在另一个图中进行合不合法的判定。这里我们以第一个图作为操作的对象,以第二个图作为判定的依据。首先想到的就是我们先将两个图都划分连通块,然后枚举第一个图任意两个连通块x,y,考虑两个连通块的点,若存在u属于x,v属于y并且u和v在图二中不属于同一个连通块,那么u和v就可以相连,这两个连通块就可以联通。并且两个连通块不能连的充要条件是这两个连通块内的所有点在图二中都属于同一个连通块内。枚举任意两个连通块显然复杂度是过不去的,我们能不能固定一个连通块(比如说连通块1),然后尝试将其他连通块与它联通,但这样会不会少连一些边?比如连通块x与连通块y都不能与1联通,但这两个能不能联通呢?考虑下刚才提到的充要条件,这两个连通块不能和1联通,说明这两个连通块内的所有点和1的所有点在图二中都属于同一个连通块内。那这两个连通块的点在图二也都属于同一个连通块内啊!肯定不能连啊。好了,那我们固定一号连通块,尝试将其他的所有连通块与它联通。显然我们找点的时候我们肯定不能枚举所有的点来判断,既然要求找到一个点对即可。我们考虑保存下当前一号连通块内的所有点在图二中的连通块编号,以及该编号中的其中一个点(方便输出方案)。当下一个连通块来的时候我们直接枚举这个连通块内的所有点来判断是否有没有符合要求的点对。并且当可以联通时,我们还需要在图二中连边,合并两个连通块,这个可以用并查集实现,但有时这两个连通块(符合要求的点对在图二中的两个连通块)都在我们维护的一号连通块内(图一中),这就需要我们维护的东西支持删除操作,这个我用了set,不想再动脑了。你以为这就结束了吗?不不不....我们发现当一号连通块内对应的在图二中的连通块个数越多,越容易与其它连通块联通,为了避免一些恶心情况(因为当前1号连通块对应的图二中的连通块个数为1,而失败联通,但之后有其他的连通块对应图二有更多的连通块,调整下顺序就能联通原本不能联通的),我们将图一中的连通块按照在图二中对应地连通块的个数排序,个数多着在前,这样我们就先尽可能的增加我们维护的一号图在二号图中的连通块的个数,之后就能尽可能多的接纳其他的连通块。总复杂度\(O(nlogn)\),多少次想放弃,但还是想坚持下去....
查看代码
//不等,不问,不犹豫,不回头.
#include
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair
#define PII pair
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=1e5+10;
int n,m1,m2,f[3][N],vis[N],num,bx[N],by[N],id[N];
struct wy{int len,v;}a[N];
vectorv[N];
mapmp;
sets; inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
} inline int getf(int op,int x){return f[op][x]==x?x:f[op][x]=getf(op,f[op][x]);} inline void init()
{
get(n);get(m1);get(m2);
rep(i,1,n) f[1][i]=f[2][i]=i;
rep(i,1,m1)
{
int get(x),get(y);
int t1=getf(1,x),t2=getf(1,y);
if(t1!=t2) f[1][t1]=t2;
}
rep(i,1,m2)
{
int get(x),get(y);
int t1=getf(2,x),t2=getf(2,y);
if(t1!=t2) f[2][t1]=t2;
}
} inline bool cmp(wy a,wy b) {return a.len>b.len;} inline void prework()
{
rep(i,1,n) f[1][i]=getf(1,i),f[2][i]=getf(2,i);
rep(i,1,n)
{
if(!vis[f[1][i]])
{
vis[f[1][i]]=1;
id[f[1][i]]=++num;
}
a[id[f[1][i]]].len++;
a[id[f[1][i]]].v=f[1][i];
}
sort(a+1,a+num+1,cmp);
rep(i,1,num) id[a[i].v]=i;
rep(i,1,n) v[id[f[1][i]]].push_back(i);
memset(vis,0,sizeof(vis));
for(auto x:v[1])
{
if(vis[f[2][x]]) continue;
vis[f[2][x]]=1;
s.insert(f[2][x]);
mp[f[2][x]]=x;
}
} inline void solve()
{
int ans=0;
rep(i,2,num)//枚举从第二个连通块开始的所有连通块,尝试与第一个连通块合并。
{
bool flag=false;
for(auto x:s)//枚举每个连通块
{
if(flag) break;
for(auto y:v[i])
{
int t=getf(2,y);
if(t!=x&&!flag)
{
bx[++ans]=mp[x];
by[ans]=y;
f[2][t]=x;
if(s.find(t)!=s.end()) s.erase(t);
flag=true;
}
else if(flag&&!vis[t])
{
vis[t]=1;
s.insert(t);
mp[t]=y;
}
}
}
}
put(ans);
rep(i,1,ans) printf("%d %d\n",bx[i],by[i]);
} int main()
{
// freopen("1.in","r",stdin);
//freopen("sol.out","w",stdout);
init();
prework();
solve();
return (0_0);
}
//以吾之血,铸吾最后的亡魂.
Codeforces Round #738 (Div. 2) D2题解的更多相关文章
- # Codeforces Round #529(Div.3)个人题解
Codeforces Round #529(Div.3)个人题解 前言: 闲来无事补了前天的cf,想着最近刷题有点点怠惰,就直接一场cf一场cf的刷算了,以后的题解也都会以每场的形式写出来 A. Re ...
- Codeforces Round #557 (Div. 1) 简要题解
Codeforces Round #557 (Div. 1) 简要题解 codeforces A. Hide and Seek 枚举起始位置\(a\),如果\(a\)未在序列中出现,则对答案有\(2\ ...
- Codeforces Round #738 (Div. 2)
Codeforces Round #738 (Div. 2) 跳转链接 A. Mocha and Math 题目大意 有一个长度为\(n\)的数组 可以进行无数次下面的操作,问操作后数组中的最大值的最 ...
- Codeforces Round #540 (Div. 3) 部分题解
Codeforces Round #540 (Div. 3) 题目链接:https://codeforces.com/contest/1118 题目太多啦,解释题意都花很多时间...还有事情要做,就选 ...
- Codeforces Round #527 (Div. 3) ABCDEF题解
Codeforces Round #527 (Div. 3) 题解 题目总链接:https://codeforces.com/contest/1092 A. Uniform String 题意: 输入 ...
- Codeforces Round #538 (Div. 2) (A-E题解)
Codeforces Round #538 (Div. 2) 题目链接:https://codeforces.com/contest/1114 A. Got Any Grapes? 题意: 有三个人, ...
- Codeforces Round #531 (Div. 3) ABCDEF题解
Codeforces Round #531 (Div. 3) 题目总链接:https://codeforces.com/contest/1102 A. Integer Sequence Dividin ...
- Codeforces Round #499 (Div. 1)部分题解(B,C,D)
Codeforces Round #499 (Div. 1) 这场本来想和同学一起打\(\rm virtual\ contest\)的,结果有事耽搁了,之后又陆陆续续写了些,就综合起来发一篇题解. B ...
- Codeforces Round #350 (Div. 2) D2. Magic Powder - 2
题目链接: http://codeforces.com/contest/670/problem/D2 题解: 二分答案. #include<iostream> #include<cs ...
随机推荐
- layui日期选择无效的问题
解决layui引入时间控件无效的问题 - 简书 (jianshu.com) 原因是因为在使用日期选择器的时候,layui源码里有一个laydate.css文件找不到 将下载的文档文件里的css文件夹, ...
- python math详解(1)
python math详解(1) 一.导入 python要调用math要进行导入 import math 二.返回值 math包里有一些值 比如 math.pi 返回pi的值 约为3.14 math. ...
- 【转】mysql实现随机获取几条数据的方法
sql语句有几种写法 1:SELECT * FROM tablename ORDER BY RAND() LIMIT 想要获取的数据条数: 2:SELECT *FROM `table` WHERE i ...
- 《exe应用程序UI自动化》
前言:有很多公司做一些客户端的应用,每次发版都要耗费人力去手动回归比较费时,那么我们就想着去怎么去驱动人为的操作变为机器的操作过程,当然想着进行UI自动 那么我们就要考虑怎么去实现exe应用程序的自动 ...
- python读取文件编码转换问题
encode(编码) decode(解码) encoding(编码格式) #-*- coding:utf-8 -*- import chardet #用于查看编码 with open(&quo ...
- NetCore5实现https请求
前言 本文主要介绍在NetCore5中,实现证书加载和https访问请求. 证书准备 首先我们先创建一个自定义的证书Kiba518.pfx. 证书创建参考:最通俗易懂的RSA加密解密指导. 然后将证书 ...
- P4755-Beautiful Pair【笛卡尔树,线段树】
正题 题目链接:https://www.luogu.com.cn/problem/P4755 题目大意 \(n\)个数字的一个序列,求有多少个点对\(i,j\)满足\(a_i\times a_j\le ...
- YbtOJ#893-带权的图【高斯消元,结论】
正题 题目链接:https://www.ybtoj.com.cn/problem/893 题目大意 给出一张\(n\)个点\(m\)条边的无向联通图,每条边正反向各有\(A,B,C\)三种边权. 保证 ...
- Kettle学习笔记(四)— 总结
目录 Kettle学习笔记(一)- 环境部署及运行 Kettle学习笔记(二)- 基本操作 kettle学习笔记(三)- 定时任务的脚本执行 Kettle学习笔记(四)- 总结 Kettle中设置编码 ...
- disruptor笔记之八:知识点补充(终篇)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...