天梯赛 L2 - 007 家庭房产 【并查集】

传送门
// 题意: 题意就不多说了. 直接开讲思路.

首先有一个家族关系, 那么肯定这个要用并查集维护, 然后家庭人数就是集合的size, 也比较好维护, 比较难做的点是维护集合中每一个点有房产的, 所以对于这种题, 就不要再用下标从1开始累加他们了, 直接用下标来代替他们的编号, 因为这个编号范围很小, 我们可以直接枚举所有在这个范围内的点, 这种题都是这种套路, 记好了! 然后就是标记出现过的点, 然后for一遍把所有集合都取出来即可. 并查集就是普通的并查集, 注意我这个写法有一个坑点就是编号可以为0, 我这个就会出bug, 所以要通过该集合的人数来判断…… 具体细节请看代码.

AC Code

const int maxn = 1e4+5;
int fa[maxn], r[maxn];
void init() {
    for (int i = 0 ; i <= maxn-4 ; i ++) {
        fa[i] = i;
        r[i] = 1;
    }
}
int Find(int x) {
    return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
void Un(int x, int y) {
    int fx = Find(x);
    int fy = Find(y);
    if (fx == fy) return ;
    if (r[fx] < r[fy]) swap(fx, fy);
    fa[fy] = fx;
    r[fx] += r[fy];
}
map<int, int>m1;
int a[maxn], b[maxn];
struct node {
    int id, num; db w1, w2;
    bool operator < (const node& _) const {
        if ((1.0*w2)/num == (1.0*_.w2)/_.num) return id < _.id;
        return (1.0*w2)/num > (1.0*_.w2)/_.num;
    }
}e[maxn];
void solve()
{
    init();
    int n; cin >> n;
    int idx = 0;
    for (int i = 1 ; i <= n ; i ++) {
        int tmp, f1, f2, son;
        cin >> tmp >> f1 >> f2;
        m1[tmp] = m1[f1] = m1[f2] = 1;
        if (f1 != -1) Un(tmp, f1);
        if (f2 != -1) Un(tmp, f2);
        int k; cin >> k;
        for (int j = 1 ; j <= k ; j ++) {
            cin >> son; m1[son] = 1;
            if (son != -1) Un(tmp, son);
        }
        cin >> a[tmp] >> b[tmp];
    }
    for (int i = 0 ; i <= maxn - 4 ; i ++) {
        if (!m1[i]) continue;
        int idx = Find(i);
        if (!e[idx].num) e[idx].id = i; // 不要用id来判断, 因为有0的存在.
        else e[idx].id = min(e[idx].id, i);
        e[idx].num++;
        e[idx].w1 += a[i]; e[idx].w2 += b[i];
    }
    int k = 0;
    for (int i = 0 ; i <= maxn - 4 ; i ++) {
        if (!e[i].num) continue;
        e[k++] = e[i];
    }
    sort(e, e+k);
    printf("%d\n", k);
    for (int i = 0 ; i < k ; i ++) {
        printf("%04d %d %.3f %.3f\n", e[i].id, e[i].num, 1.0*e[i].w1/e[i].num, 1.0*e[i].w2/e[i].num);
    }
}

你可能感兴趣的:(简单学习日常)