【CF2060E Graph Composition】题解
闲话
不知道为什么,这场 CF 我觉得 D 不可做,但是 E 很可做。(哦因为我太菜了)
思路
这道题要求通过增、删
先考虑删边。很显然,如果
然后删完边,考虑加边。这个时候
代码
实现需要两个并查集。这里连边时如果是将原本不属于同意连通块的点连接,则返回 1,反之返回 0,以此计算连通块数目。
fa 数组:点在并查集中的父亲。
rt 函数:点在并查集中的根。
unite 函数:连接两个点。
join 函数:判断两个点是否在同一个连通块内。
#include<bits/stdc++.h>
#define ll long long
#define pb emplace_back
#define pii pair<int,int>
#define fir first
#define sec second
//#define
using namespace std;
int t;
int n,m1,m2,fa1[200005],fa2[200005],u[200005],v[200005];
int rt1(int x){return x==fa1[x]?x:fa1[x]=rt1(fa1[x]);}
int rt2(int x){return x==fa2[x]?x:fa2[x]=rt2(fa2[x]);}
int unite1(int x,int y){
int fax=rt1(x),fay=rt1(y);
if(fax!=fay){
fa1[fax]=fay;
return 1;
}
return 0;
}
int join1(int x,int y){
int fax=rt1(x),fay=rt1(y);
if(fax!=fay){
// fa1[fax]=fay;
return 0;
}
return 1;
}
int unite2(int x,int y){
int fax=rt2(x),fay=rt2(y);
if(fax!=fay){
fa2[fax]=fay;
return 1;
}
return 0;
}
int join2(int x,int y){
int fax=rt2(x),fay=rt2(y);
if(fax!=fay){
return 0;
}
return 1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// t=1;
cin>>t;
while(t--){
cin>>n>>m1>>m2;
for(int i=1;i<=n;i++)fa1[i]=fa2[i]=i;
int cnt1=n,cnt2=n;
for(int i=1;i<=m1;i++)cin>>u[i]>>v[i];
for(int i=1;i<=m2;i++){
int x,y;cin>>x>>y;
cnt2-=unite2(x,y);
}
int ans=0;
for(int i=1;i<=m1;i++){
int flag2=join2(u[i],v[i]);
// cout<<i<<":"<<flag1<<" "<<flag2<<"\n";
if(flag2==0)ans++;
else cnt1-=unite1(u[i],v[i]);
}
// cout<<cnt1<<" "<<cnt2<<" ";
ans+=cnt1-cnt2;
cout<<ans<<"\n";
}
return 0;
}