训练情况
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 \timnes (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;
}