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 ...
随机推荐
- 支付宝openssl_sign(): supplied key param cannot be coerced into a private key in
先说一下,生成rsa 私钥 公钥的方法,以ubuntu 为例sudo apt-get install openssl # 先装上这个库genrsa -out rsa_private_key.pem 1 ...
- 华为云计算IE面试笔记-桌面云中的用户组、虚拟机模板、模板虚拟机、虚拟机组和桌面组的关系及区别。发放完整复制和链接克隆虚拟机时,步骤有什么区别,要怎么选择桌面组?
概念解释: 模板虚拟机:FC上创建的裸虚拟机,用于制作不同类型的虚拟机模板. 虚拟机模板:用于创建虚拟机的模板,对裸虚拟机(模板虚拟机)进行配置或自定义安装软件后,转为模板.虚拟机模板类型有完整复制, ...
- iOS之内存管理-字节对齐
字节对齐 1 struct Mystruct1{ 2 char a; //1字节 3 double b; //8字节 4 int c; //4字节 5 short d; //2字节 6 }Mystru ...
- phpmyadmin 设置密码
例如 xampp 安装路径为 /opt/lampp/, copy 一份默认的配置 cp /opt/lampp/phpmyadmin/libraries/config.default.php /opt/ ...
- 在CentOS 6中安装和配置OrientDB社区版
OrientDB概述: OrientDB是一个开源NoSQL非关系型数据库管理系统. NoSQL数据库提供了一种用于存储和检索引用除表式数据之外的数据(例如文档数据或图形数据)的NO关系或非关系数据的 ...
- 学校选址(ArcPy实现)
一.背景 合理的学校空间位置布局,有利于学生的上课与生活.学校的选址问题需要考虑地理位置.学生娱乐场所配套.与现有学校的距离间隔等因素,从总体上把握这些因素能够确定出适宜性比较好的学校选址区. 二.目 ...
- luogu1081 开车旅行2012 D1T3 (倍增,set,O2)
题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i ...
- ReentrantLock可重入锁、公平锁非公平锁区别与实现原理
ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁 ReentrantLock公平锁和不公平锁实现原理 公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取 ...
- C/C++入门级小游戏——开发备忘录
很多工科的学生在大一都有一门课程,叫C语言程序设计.大概就是装个IDE然后和一个黑乎乎的窗口打交道,期末到了考完试就结束了.然而很多人可能都有一个疑惑:C语言究竟能干什么?除开嵌入式单片机这些高大上的 ...
- Longhorn 云原生容器分布式存储 - 故障排除指南
内容来源于官方 Longhorn 1.1.2 英文技术手册. 系列 Longhorn 是什么? Longhorn 云原生容器分布式存储 - 设计架构和概念 Longhorn 云原生容器分布式存储 - ...