题目描述
知识点: 并查集
思路: 本题为并查集的一道扩展版,需要维护额外的信息。细心点即可。需要开辟的维护数组有:集合最小的id,集合中的元素个数,集合中的面积总和,集合中的房子数量。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 10010;
double num_set[N],num_family[N],num_area[N],small_id[N];
int p[N],n;
bool v[N];
int find(int x){
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
struct Res{
int id,family_cnt;
double avg_set,avg_area;
bool operator < (const Res r) const{
if(abs(avg_area - r.avg_area) > 1e-5) return avg_area > r.avg_area;
return id < r.id;
}
};
void merge_family(int x,int y){
v[x] = 1,v[y] = 1;
x = find(x);
y = find(y);
if(x != y){
num_set[p[y]] += num_set[p[x]];
num_family[p[y]] += num_family[p[x]];
num_area[p[y]] += num_area[p[x]];
small_id[p[y]] = min(small_id[p[y]],small_id[p[x]]);
p[x] = p[y];
}
}
int main(){
for(int i = 0;i < N;i++){
p[i] = i;
num_family[i] = 1;
small_id[i] = i;
}
cin>>n;
while(n--){
vector<int> children;
int id,p1,p2,k,child;
double sets,total_area;
cin>>id>>p1>>p2>>k;
for(int i = 0;i < k;i++) {
int c;
cin>>c;
children.push_back(c);
}
cin>>sets>>total_area;
int x = find(id);
v[id] = 1;
num_set[p[x]] += sets;
num_area[p[x]] += total_area;
if(p1 != -1) merge_family(id,p1);
if(p2 != -1) merge_family(id,p2);
for(int i = 0;i < children.size();i++)
merge_family(id,children[i]);
}
vector<Res> res;
for(int i = 0;i < 10000;i++){
if(v[i] && p[find(i)] == i){
res.push_back({small_id[i],num_family[i],(double)num_set[i]/num_family[i],(double)num_area[i]/num_family[i]});
}
}
sort(res.begin(),res.end());
cout<<res.size()<<endl;
for(auto &i : res){
printf("%04d %d %.3lf %.3lf\n",i.id,i.family_cnt,i.avg_set,i.avg_area);
}
return 0;
}