日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/3 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 codeforces1559 D2. Mocha and Diana (Hard Version)(并查集+启发式合并+随机化) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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)(并查集+启发式合并+随机化)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。