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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

CodeForces - 1445E Team-Building(可撤销并查集)

發布時間:2024/4/11 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CodeForces - 1445E Team-Building(可撤销并查集) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一張有 n 個點和 m 條邊的圖,每個點都有一個種類,共有 k 個種類,現在要從 k 個種類中每次選出兩種,對所有?C( k , 2 ) 種組合單獨討論,對于選出的兩個種類中,包含的所有的點以及其連邊所組成的子圖,如果該子圖可以拆分成二分圖,那么答案加一

題目分析:參考博客:https://blog.csdn.net/Zenith_Habitant/article/details/109451857

k 的范圍很大,正難則反,考慮計算不合法的組合個數,然后由總的合法個數減去就是答案了

首先看到題目中的二分圖,不難想到其定義為:“不含有奇環的一個圖”,而判斷二分圖的兩種方法,一種是直接 dfs 染色,另一種方法就是對每個點建立虛點然后并查集維護,可以參考:CH - 4901 關押罪犯

因為總的邊數只有 m 條邊,換句話說,假設每條邊 ( x , y ) 連接的 x 和 y 都屬于不同的種類,最終也只有 m 種組合方案,所以非法的種類數最多只有 m 種

所以對于每條邊 ( x , y ) 分類討論,設 type[ x ] 是 x 的種類:

  • 如果 type[ x ] == type[ y ],直接用并查集將其合并即可
  • 如果 type[ x ] != type[ y ],將其加入所有,連接( type[ x ] , type[ y ] ) 這兩個種類的邊的集合中去
  • 然后對于每個種類自己單獨的連通塊內,如果出現了奇環,說明當前這個種類無論和哪個組合匹配,都不可能產生貢獻了,對于這些種類單獨拿出來即可

    然后就是對合并任意兩個種類的那些邊分組,依次合并,看看這兩個種類組合的話是否會產生貢獻,這里需要注意的是,因為對于合并每兩個組的邊集都是相互獨立的,所以在進行完一次 “ 合并 ”,檢查出答案后,需要及時撤銷,這樣就可以保證算法的正確性了,關于撤銷可以直接用并查集的撤銷來實現

    代碼:
    ?

    //#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;map<pair<int,int>,vector<pair<int,int>>>mp;//map[{type_a,type_b}]={(u1,v1),(u2,v2)...(uk,vk)}//表示連接兩個組的邊 struct revo {int fax,fay;int rkx,rky; };int a[N],b[N],f[N],rk[N],type[N],tot;bool fail[N];stack<revo>st;int find(int x) {return f[x]==x?x:find(f[x]); }void merge(int x,int y) {int xx=find(x),yy=find(y);revo temp;temp.fax=xx,temp.fay=yy;temp.rkx=rk[xx],temp.rky=rk[yy];st.push(temp);if(rk[xx]>rk[yy])swap(xx,yy);f[xx]=yy;rk[yy]=max(rk[yy],rk[xx]+1); }void revocation(int k) {while(k--){revo node=st.top();st.pop();f[node.fax]=node.fax;f[node.fay]=node.fay;rk[node.fax]=node.rkx;rk[node.fay]=node.rky;} }void init() {for(int i=1;i<N;i++){f[i]=i;rk[i]=1;} }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();int n,m,k;LL ans=0;scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++)scanf("%d",type+i);for(int i=1;i<=m;i++)scanf("%d%d",a+i,b+i);for(int i=1;i<=m;i++)//同一種類的邊,直接維護即可 {if(type[a[i]]==type[b[i]]){int xx=find(a[i]),yy=find(b[i]);if(xx!=yy)merge(a[i],b[i]+n),merge(b[i],a[i]+n);elsefail[type[a[i]]]=true;}}for(int i=1;i<=m;i++)//連接兩個不同種類的邊,將其歸類 {if(type[a[i]]==type[b[i]])continue;if(fail[type[a[i]]]||fail[type[b[i]]])continue;if(type[a[i]]>type[b[i]])swap(a[i],b[i]);mp[make_pair(type[a[i]],type[b[i]])].emplace_back(a[i],b[i]);}for(auto node:mp)//node.second=vector<pair<int,int>>{int cnt=0;for(auto it:node.second)//it=pair<int,int>=(u,v){int x,y;tie(x,y)=it;int xx=find(x),yy=find(y);if(xx!=yy)merge(x,y+n),merge(y,x+n),cnt+=2;else{ans--;break;}}revocation(cnt);}LL cnt=0;for(int i=1;i<=k;i++)if(!fail[i])cnt++;ans+=cnt*(cnt-1)/2;printf("%lld\n",ans);return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的CodeForces - 1445E Team-Building(可撤销并查集)的全部內容,希望文章能夠幫你解決所遇到的問題。

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