【vjudge训练记录】大一寒假专项训练——并查集
训练情况

A题
并查集模板,求班级最多人数和班级数,可以使用map进行统计,取父节点塞进map里面,取最大值和size即可
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
const int N = 1e5 + 3;
int fa[N];
int n,m;
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void Union(int x,int y){
x = Find(x); y = Find(y);
if(x == y) return;
fa[y] = x;
}
void solve(){
cin>>n>>m;
for(int i = 1;i<=n;i++) fa[i] = i;
map<int,int> v;
while(m--){
int x,y; cin>>x>>y;
Union(x,y);
}
for(int i = 1;i<=n;i++) v[Find(i)]++;
int ma = 0;
for(auto i:v) ma = max(ma,i.second);
cout<<v.size()<<" "<<ma<<endl;
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
B题
并查集模板,判断是否在一个集合内,只需要查询两个点的父节点是否相同
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 3;
int n,m;
int fa[N];
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void Union(int x,int y){
x = Find(x); y = Find(y);
if(x == y) return;
fa[y] = x;
}
void solve(){
cin>>n>>m;
for(int i = 1;i<=n;i++) fa[i] = i;
while(m--){
int opt,x,y; cin>>opt>>x>>y;
if(opt == 1) Union(x,y);
else if(opt == 2){
if(Find(x) == Find(y)) cout<<"Y"<<endl;
else cout<<"N"<<endl;
}
}
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
C题
维护亲戚的亲戚是亲戚这一传递关系,并查集模板
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
const int N = 5e3 + 3;
int n,m,p;
int fa[N];
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void Union(int x,int y){
x = Find(x); y = Find(y);
if(x == y) return;
fa[y] = x;
}
void solve(){
cin>>n>>m>>p;
for(int i = 1;i<=n;i++) fa[i] = i;
while(m--){
int x,y; cin>>x>>y;
Union(x,y);
}
while(p--){
int x,y; cin>>x>>y;
if(Find(x) == Find(y)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
D题
并查集模板,只是这次需要维护一下字符串和节点的映射关系,直接使用map维护
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
const int N = 2e4 + 3;
int n,m;
int fa[N];
map<string,int> toi;
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void Union(int x,int y){
x = Find(x); y = Find(y);
if(x == y) return;
fa[y] = x;
}
void solve(){
cin>>n>>m;
for(int i = 1;i<=n;i++) fa[i] = i;
int tot = 0;
for(int i = 1;i<=n;i++){
string s; cin>>s;
toi[s] = ++tot;
}
while(m--){
string x,y; cin>>x>>y;
Union(toi[x],toi[y]);
}
int k; cin>>k;
while(k--){
string x,y; cin>>x>>y;
if(Find(toi[x]) == Find(toi[y])) cout<<"Yes."<<endl;
else cout<<"No."<<endl;
}
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
E题
并查集模板,只是这次变成二维平面,点 \((x,y)\) 对应的节点是 \(n \times (x-1) + y\),其中 \(n\) 为行数
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
const int N = 2e6 + 3;
int n,m,k;
int fa[N];
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void Union(int x,int y){
x = Find(x); y = Find(y);
if(x == y) return;
fa[y] = x;
}
void solve(){
cin>>n>>m>>k;
for(int i = 1;i<=n*m;i++) fa[i] = i;
while(k--){
int x,y; cin>>x>>y;
Union(x,y);
}
set<int> ans;
for(int i = 1;i<=n*m;i++) ans.insert(Find(i));
cout<<ans.size()<<endl;
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
F题
考察比较灵活的并查集,我们需要维护数字集合中的最大值,所以我们需要把父节点设为集合内数字的最大值+1,在每次修改数字的时候,直接查询父节点
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
const int N = 1e6 + 3;
int fa[N];
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void solve(){
int n; cin>>n;
for(int i = 1;i<=N-3;i++) fa[i] = i;
vector<int> a(n + 1);
for(int i = 1;i<=n;i++) cin>>a[i];
for(int i = 1;i<=n;i++){
a[i] = Find(a[i]);
fa[a[i]] = Find(a[i])+1;
cout<<a[i]<<" ";
}
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}

浙公网安备 33010602011771号