题解 | #叠积木(带权并查集,记录到根节点举例和本列积木数量)#

叠积木

https://ac.nowcoder.com/acm/problem/235622

这道题维护的附加信息是某一块积木下面还有多少块积木,并查集来写用两个数组 d[ ] 和 cnt [ ],   d [ ]表示这块积木到上一个节点有多少块积木
比如 x的祖宗节点是 p[x],那d[x]代表的就是x到最下面一块积木也就是祖宗节点p[x]的数量  d[ i ]:i 距离根节点(队头)的距离
合并的时候只需要加上下面一列积木就是自己下面的积木数量
cnt[ i ]:i 所在的连通块有多少个元素( i 所在那一列的积木数目 )
但d[ ] 数组的一个维护就要依靠cnt数组来解决,cnt记录某一列有多少积木,当然cnt [ 祖宗节点 ]才有效
所以在连接两列积木时,只需要上面一列的祖宗节点也就是最下面那块积木 x 指向下面一列积木的祖宗节点 y ,那上面一列祖宗节点 x 到他的祖宗节点 y 的积木数量d [ x ] = cnt [ y ]
那这两列结合之后的积木数量就一个数 cnt [ y ] += cnt [ x ];

图中size代表的是cnt
会了的话可以试试这题
// 总所周知如果x!=p[x],那么只需要找p[x]的祖宗节点就是x的祖宗节点,只会找一次,这个不好解释,可以自己模拟一下

#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
int n;
int fa[N];
int d[N];
int cnt[N];   
int find2(int x) {
     
    if (fa[x] != x) {
        int t = find2(fa[x]);//向上递推找祖父
        d[x] += d[fa[x]];//向下堆叠积木数量
        fa[x] = t;
    }
    return fa[x];
}
void unite(int x, int y) {//将x叠到y所在的积木列的上面
    int f1 = find2(x);
    int f2 = find2(y);
    if (f1 != f2) {//祖父不相同,要继续堆叠积木数量
        fa[f1] = f2;
        d[f1] = cnt[f2];   //cnt代表f2所在积木列的数量
        cnt[f2] += cnt[f1];   //结合之后祖宗节点是f2 ,这一列的数量就等于之前两列数量之和
    }
}
int main() {
    cin >> n;
    for (int i = 1; i < N; i++)
    {
        fa[i] = i;
        d[i] = 0;
        cnt[i] = 1;
    }    //初始化,d[]是本身下面的积木数量,初始为0,cnt是这一列的积木数量,初始时每一列都为1
    for (int i = 1; i <= n; i++) {
        char c;
        cin >> c;
        if (c == 'M') {
            int x, y;
            cin >> x >> y;
            unite(x, y);   //堆叠操作
        }
        else {
            int x;
            cin >> x;
            find2(x);//计算d[x]的数量   
            cout << d[x] << endl;
        }
 
    }
    return 0;
}
全部评论
1
点赞 回复 分享
发布于 2023-08-11 17:51 江西
2
点赞 回复 分享
发布于 2023-08-11 17:51 江西
3
点赞 回复 分享
发布于 2023-08-11 17:51 江西

相关推荐

10-25 00:32
香梨想要offer:感觉考研以后好好学 后面能乱杀,目前这简历有点难
点赞 评论 收藏
分享
6 收藏 评论
分享
牛客网
牛客企业服务