D2. Mocha and Diana (Hard Version)

RunningBeef题解
首先将图1的点与1号点所在的连通块相连,图2类似。

然后就是在图1和图2中选择没有和1号点在同一个连通块的点,能连边就连。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg;
}const int N=100010;int n,m1,m2;
struct dsu
{vector<int> fa;dsu(int n):fa(n){iota(fa.begin(),fa.end(),0);}int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}void merge(int x,int y){x=find(x),y=find(y);if(x>y) swap(x,y);fa[y]=x;}
};
int main()
{n=rd(),m1=rd(),m2=rd();dsu t1(n+1),t2(n+1);while(m1--){int u=rd(),v=rd();t1.merge(u,v);}while(m2--){int u=rd(),v=rd();t2.merge(u,v);}vector<int> v1,v2;vector<pair<int,int>> ans;for(int i=2;i<=n;i++) {if(t1.find(i)!=1&&t2.find(i)!=1) {ans.push_back({1,i});t1.merge(1, i);t2.merge(1, i);}if(t1.find(i)!=1)v1.push_back(i);if(t2.find(i)!=1)v2.push_back(i);}while(!v1.empty()&&!v2.empty()) {if(t1.find(v1.back())==1&&t2.find(v1.back())==1) {v1.pop_back();continue;}   if(t1.find(v2.back())==1&&t2.find(v2.back())==1){v2.pop_back();continue;}ans.push_back({v1.back(),v2.back()});t1.merge(v1.back(),v2.back());t2.merge(v1.back(),v2.back());v1.pop_back();v2.pop_back();} printf("%d\n",(int)ans.size());for(auto t:ans) printf("%d %d\n",t.first,t.second);
}

Code2

晚上刷b站刷到neal大神,发现这个随机做法很吊,于是写一下,顺便学习下pb_ds

n\color{black}\text nneal\color{red}\text {eal}eal大神的做法

首先将图1连边后变成若干个连通块,同样将图2连边后也变成若干个连通块。
最终能够连边的数量一定是让某个图变成一棵树。于是对于连边的答案数量是固定的。

对于每次连边,我们随机从图一或者图二中随机随机选择某个连通块的某两个点,看看它们是否能够连边,如果能就连上,就这样随机连边。

yy一下感觉每次连边成功的概率非常大。why?

考虑冲突的概率:假设图1中有x个连通块,图2中有y个连通块

不冲突的大致概率1−1x2−1y2+cst1-\frac{1}{x^2}-\frac{1}{y^2}+\text{cst}1−x21​−y21​+cst

图一冲突或者图二冲突。
cst\text{cst}cst根据容斥原理在两个图中都冲突的概率。

x或y都必须大于1,于是概率会大于12\frac{1}{2}21​,已经比较大了。


需要维护并查集有哪些点,可以用个vector<int> lis维护,合并的时候启发式合并。

维护连通块需要用pb_ds库,我们需要快速find_by_order,并且支持快速插入删除,需要平衡树。

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
using ll=long long;template <class T=int> T rd()
{T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg;
}
template<typename T>
using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;const int N=100010;int n,m1,m2;
struct dsu
{vector<int> fa;vector<vector<int>> lis;int cnt; //连通块的数量dsu(int n){fa.resize(n);lis.resize(n);cnt=n-1;for(int i=0;i<n;i++) fa[i]=i,lis[i]={i};}int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}bool merge(int x,int y){x=find(x),y=find(y);if(x==y) return false;if(lis[x].size()<lis[y].size()) swap(x,y);lis[x].insert(lis[x].end(),lis[y].begin(),lis[y].end());lis[y].clear();fa[y]=x;cnt--;return true;}
}; std::mt19937 rnd(233);
int main()
{n=rd(),m1=rd(),m2=rd();dsu t1(n+1),t2(n+1);while(m1--){int u=rd(),v=rd();t1.merge(u,v);}while(m2--){int u=rd(),v=rd();t2.merge(u,v);}int need=min(t1.cnt,t2.cnt)-1;ordered_set<int> rt1,rt2;for(int i=1;i<=n;i++){if(t1.find(i)==i) rt1.insert(i);if(t2.find(i)==i) rt2.insert(i);}// 随机从图中的某个连通块找某个点auto get_random=[&](dsu &t,ordered_set<int> &rt)->int{int u=*rt.find_by_order((rnd()%rt.size()+rt.size())%rt.size());return t.lis[u][(rnd()%t.lis[u].size()+t.lis[u].size())%t.lis[u].size()];};// 随机找一个图auto get_random_node=[&]()->int{if(rnd()%2==0) return get_random(t1,rt1);else return get_random(t2,rt2);};vector<pair<int,int>> ans;while(ans.size()<need){// 随机出两点 a b看看是否能够连边int a=get_random_node();int b=get_random_node();if(t1.find(a)!=t1.find(b)&&t2.find(a)!=t2.find(b)){ans.push_back({a,b});rt1.erase(rt1.find(t1.find(a)));rt1.erase(rt1.find(t1.find(b)));rt2.erase(rt2.find(t2.find(a)));rt2.erase(rt2.find(t2.find(b)));t1.merge(a,b);t2.merge(a,b);rt1.insert(t1.find(a));rt2.insert(t2.find(a));}}printf("%d\n",(int)ans.size());for(auto t:ans) printf("%d %d\n",t.first,t.second);
}

codeforces1559 D2. Mocha and Diana (Hard Version)(并查集+启发式合并+随机化)相关推荐

  1. Mocha and Diana (Easy Version) 并查集维护两片森林

    题意 : 给两片n个节点的森林,每次分别在两片森林的u和v节点之间加一条边,要求仍然是两片森林,求最多能加多少条边. 1≤

  2. D2. Mocha and Diana (Hard Version)

    参考博客了博客 同时也参考了cf评论中humbertoyusta的题解 然后详细的对它的最后一步进行了一个证明 先说下题意: 给你两个结点数相同的2个森林它有n个点,你每次同时给两个森林的同一对结点连 ...

  3. CodeForces - 1559D2 Mocha and Diana (Hard Version)(思维)

    题目链接:点击查看 题目大意:给出两棵森林,每次可以同时在两个森林中增加同一条边,问最多可以增加多少条边,使得两个森林仍然还是森林 题目分析:结论参考至:https://blog.csdn.net/R ...

  4. D1. Coffee and Coursework (Easy version) and D2. Coffee and Coursework (Hard Version)

    http://codeforces.com/contest/1118/problem/D1 http://codeforces.com/contest/1118/problem/D2 题意:有n杯咖啡 ...

  5. D2. Coffee and Coursework (Hard Version)(思维+贪心)

    https://codeforces.com/problemset/problem/1118/D2 思路: 第一眼能看出答案能二分把.然后这题和前缀和不同,虽然每次减的是固定的,但是前缀先加起来会减出 ...

  6. codeforces(D2. Coffee and Coursework (Hard Version))二分答案

    这题一看很容易想到二分,但我一开始想偏了,我是想枚举天数,然后二分去验证天数是否满足,但是这样二分验证天数是否满足这一步卡住了,写不出来. 然后我改成二分天数,验证天数是否满足这一步改成暴力计算,这样 ...

  7. Codeforces Round #738 (Div. 2)

    Codeforces Round #738 (Div. 2) 文章目录 A 题解: 代码: B 题意: 题解: 代码: C 题意: 题解: 代码: D1 题意: 题解: 代码: 题号 题目 知识点 A ...

  8. codeforces:ProblemMset

    最近一个月在codeforces上做的题(做个记录) 后面太多了就不把代码一一放出了,只放置了链接,可根据链接找到提交的代码. 最小子矩阵 #include <iostream> #inc ...

  9. CF杂题训练(交互题不做,2500以上的看情况吧)

    CF专练 CF1562 A The Miracle and the Sleeper B Scenes From a Memory C Rings D Two Hundred Twenty One E ...

最新文章

  1. 中国芯片研究再获国际顶会最佳论文提名!清华魏少军、刘雷波团队出品
  2. win2012 R2的ntp时间同步设置解析
  3. 网易云信牵手有道乐读,解密「终身阅读者」背后的技术力量
  4. Collection集合概述
  5. JavaFX滚动事件
  6. WeakReference与SoftReference
  7. 【LeetCode笔记】54. 螺旋矩阵(Java、迭代、递归)
  8. java 自定义注解+AOP实现日志记录
  9. mongodb和mysql的语法_Mongodb和mysql的区别
  10. 组策略不让你登陆你怎么办
  11. jmc线程转储_Java线程转储– VisualVM,jstack,kill -3,jcmd
  12. 数据结构与算法python—9.二叉树及python实现
  13. 细说API – 认证、授权和凭证
  14. MySQL中boolean类型
  15. IntelliJ-IDEA-Debug技巧
  16. 联通光纤猫虚拟服务器设置,联通光猫连接无线路由器怎么设置?
  17. AI Studio 精品项目 | 基于Few-shot Learning实现中文科学文献学科分类
  18. procmon符号配置
  19. 关于几篇数据挖掘的文章(2)
  20. 2020北航计算机夏令营机试题目个人理解

热门文章

  1. 单片机矩阵消抖延时c语言,单片机矩阵按键定时器消抖程序源码
  2. 计算机函数公式中怎么合并合并,Excel用函数和公式瞬间实现把表格全部合并到一个表中去...
  3. c语言怎么让图形界面单独显示,「分享」C语言如何编写图形界面
  4. 151. 翻转字符串里的单词(思路+详解)
  5. 「软件项目管理」一文详解软件配置管理计划
  6. 一文了解贪心算法和回溯算法在前端中的应用
  7. 『软件工程6』详解软件项目管理之软件范围与估算
  8. 高等数学下-赵立军-北京大学出版社-题解-练习10.3
  9. mysql查询语句能否让一个字段不显示出来_天天写order by,你知道Mysql底层如何执行吗?
  10. 广义表的学习(原理和代码)