题目
题意: 给定n个人的编号、父母的编号、孩子的编号、他拥有的房产数量、房产面积,按人均房产面积降序、如有并列按编号升序的形式输出每个家庭的相关信息。
思路: 经典的pta题目,很麻烦。用并查集维护每个人属于哪个家庭。有一个好写法就是最后输入完成后,将每个点的信息统一更新到他所在树上的根节点上,最后排序输出即可。
时间复杂度: O(nlogn)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,m,k,T;
struct node{
int id = 999999; //最小编号
int num = 0; //人数
int tot; //几套房子
double av = 0; //人均面积
bool operator<(const node&rhs)
{
if(av != rhs.av) return av > rhs.av;
return id < rhs.id;
}
}a[N];
int fa[N];
bool vis[N];
int find(int x)
{
return x==fa[x]?x:fa[x] = find(fa[x]);
}
void Merge(int u,int v)
{
u = find(u),v = find(v);
if(u != v)
{
fa[v] = u;
}
}
void solve()
{
for(int i=0;i<=9999;++i) fa[i] = i;
cin>>n;
for(int i=0;i<n;++i)
{
int x; int f,m; int num;
cin>>x>>f>>m;
vis[x] = 1;
a[x].id = x;
if(f != -1) Merge(x,f),vis[f] = 1;
if(m != -1) Merge(x,m),vis[m] = 1;
cin>>num;
for(int j=0;j<num;++j)
{
int t; cin>>t;
vis[t] = 1;
Merge(x,t);
}
cin>>a[x].tot>>a[x].av;
}
for(int i=0;i<=9999;++i)
{
if(vis[i])
{
int u = find(i);
a[u].id = min(a[u].id,i);
a[u].num ++ ;
if(u == i) continue; //不能反复加
a[u].tot += a[i].tot;
a[u].av += a[i].av;
}
}
int ans = 0;
for(int i=0;i<=9999;++i)
{
if(vis[i] && find(i) == i)
{
a[i].av /= a[i].num;
ans++;
}
}
cout<<ans<<"\n";
sort(a,a+9999);
for(int i=0;i<=9999;++i)
{
if(a[i].id <= 9999 && a[i].num > 0)
{
printf("%04d %d %.3lf %.3lf\n",a[i].id,a[i].num,1.0*a[i].tot/a[i].num,a[i].av);
}
}
}
signed main(void)
{
solve();
return 0;
}