先是自己使用并查集+map进行大模拟写了一份很麻烦的代码,一直过不去测试点3和4,结果是因为使用了ios::sync_with_stdio(0),cin.tie(0),cout.tie(0),导致不能让程序在输入输出中同时使用了C++的输入输出流和C标准库的输入输出函数,后来注释掉就过了,代码如下:
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
typedef long long ll;
const int N = 10100;
const int mod = 998244353;
int parent[N],n;
struct box{
int id;
int num;
int hous;
int area;
};
int find(int x){
if(parent[x] != x){
parent[x] = find(parent[x]);
}
return parent[x];
}
void merge(int x,int y){
parent[find(x)] = find(y);
}
bool cmp(box x,box y){
if(x.area * y.num == y.area * x.num){
return x.id < y.id;
}
return x.area * y.num > y.area * x.num;
}
void solve() {
//并查集初始化
for(int i = 0 ; i <= 10000; i++){
parent[i] = i;
}
cin>>n;
map<int,pair<int,int>> value;
map<int,int> tmp;
for(int i = 0 ; i < n; i++){
int bh,fa,ma;
cin>>bh>>fa>>ma;
tmp[bh];
if(fa != -1){
merge(bh,fa);
tmp[fa];
}
if(ma != -1){
merge(bh,ma);
tmp[ma];
}
int k;
cin>>k;
for(int i = 0 ; i < k ; i++){
int x;
cin>>x;
tmp[x];
merge(bh,x);
}
int fz,mj;
cin>>fz>>mj;
value[bh].first = fz;
value[bh].second = mj;
}
map<int,int> fam,minans,h1,a1;
int cnt = 0;
// for(auto it : tmp){
// minans[find(it.first)] == -1;
// }
map<int,int> vt;
for(auto it : tmp){
fam[find(it.first)]++;
h1[find(it.first)] += value[it.first].first;
a1[find(it.first)] += value[it.first].second;
if(vt[find(it.first)] == 0){
vt[find(it.first)] = 1;
minans[find(it.first)] = it.first;
}else minans[find(it.first)] = min(it.first,minans[find(it.first)]);
}
vector<box> ans;
for(auto it : minans){
ans.push_back({it.second,fam[find(it.first)],h1[find(it.first)],a1[find(it.first)]});
}
cnt = fam.size();
cout<<cnt<<endl;
sort(ans.begin(),ans.end(),cmp);
for(int i = 0 ; i < ans.size() ; i++){
printf("%04d %d %.3lf %.3lf\n",ans[i].id,ans[i].num,ans[i].hous*1.0/ans[i].num
,ans[i].area*1.0/ans[i].num);
}
}
signed main() {
// ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int tt = 1;
// cin >> tt;
while (tt--) {
solve();
}
return 0;
}
看了一个讲解视频后,学到了并查集的带权合并,就是额外开几个数组,合并的时候把对应的value也加上即可,注意我们要让最小的成为一个并查集(家庭)的代表,所以在合并的时候就判断一下,如果xx > yy 就交换,还要注意的是,因为代码中fa没有初始化,默认全为0,所以需要对0进行特殊处理,不然默认fx[0=0,导致如果没有0,结果却有0,所以,我们就初始化fa[0] = -1,还需要在find中对0进行特判,防止越界。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
typedef long long ll;
const int N = 10100;
const int mod = 998244353;
int fa[N],pnum[N],hnum[N],anum[N];
vector<int> ship[N];
int find(int x){
if(fa[x] == -1) return -1;
if(x == fa[x]){
return x;
}
else return fa[x] = find(fa[x]);
}
void merge(int x,int y){
int xx = find(x),yy = find(y);
if(xx == yy) return;
if(xx > yy) swap(xx,yy); //保证代表这个家庭的是最小的
fa[yy] = xx;
pnum[xx] += pnum[yy];
hnum[xx] += hnum[yy];
anum[xx] += anum[yy];
return;
}
struct box{
int id,p_num,h_num,a_num;
double per1,per2;
bool operator < (const box &t) const{
if(per2 != t.per2) return per2 > t.per2;
else return id < t.id;
}
};
vector<box> ans;
void solve() {
int n;
cin>>n;
fa[0] = -1; //特殊处理0,
for(int i = 1 ; i <= n ; i++){
int tid,dad,mom,sonk,son;
cin>>tid>>dad>>mom>>sonk;
for(int j = 1 ; j <= sonk ; j++){
cin>>son;
ship[tid].push_back(son);
fa[son] = son;
pnum[son] = 1;
}
if(dad != -1){
ship[tid].push_back(dad);
fa[dad] = dad;
pnum[dad] = 1;
}
if(mom != -1){
ship[tid].push_back(mom);
fa[mom] = mom;
pnum[mom] = 1;
}
fa[tid] = tid,pnum[tid] = 1;
cin>>hnum[tid]>>anum[tid];
}
for(int i = 0 ; i < 10000 ; i++){
for(int j = 0 ; j < ship[i].size() ; j++){
merge(i,ship[i][j]); //执行合并操作
}
}
for(int i = 0 ; i < 10000 ; i++){
if(i == find(i)){
ans.push_back({i,pnum[i],hnum[i],anum[i],
hnum[i]*1.0/pnum[i],anum[i]*1.0/pnum[i]});
}
}
sort(ans.begin(),ans.end());
cout<<ans.size()<<endl;
for(int i = 0 ; i < ans.size() ; i++){
printf("%04lld %lld %.3lf %.3lf\n",ans[i].id,
ans[i].p_num,ans[i].per1,ans[i].per2);
}
}
signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int tt = 1;
// cin >> tt;
while (tt--) {
solve();
}
return 0;
}