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

叠积木

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;
}
全部评论
有个问题我比较疑惑我是这样写的, 就是查询的时候, 不去修改任何的d 和cnt ,但是在合并的时候会做, 结果我做下来就是错误的: int find(int x ) { if (p[x]!=x) { int t = find(p[x]); // d[x] += d[p[x]]; p[x] = t; } return p[x]; } void move(int a, int b) { // move a to b int ra = find(a) , rb = find(b); int &size_a = cnt[ra] , &size_b = cnt [rb]; int above_a = size_a - d[a]; // include a p[a] = rb; size_a -= above_a; d[a] = size_b; size_b += above_a; }
点赞 回复 分享
发布于 2025-03-10 16:45 上海

相关推荐

昨天 13:24
已编辑
江西农业大学 后端工程师
最近或许大家都听说xxxx厂裁员,无论前端,后端,大数据,测试,运维,人人可危,&nbsp;“前端死了,后端也死了,JAVA崩盘了,你们这群搞大模型的真是码奸”这次AI真的会让我们无路可走吗????????太阳底下已经没有新鲜事了旧的生产力的消失,必然有新的生产力诞生马车夫消失&nbsp;→&nbsp;汽车司机、修车工、石油工业诞生,从业人数是马车夫的百倍手工纺织女工消失&nbsp;→&nbsp;纺织机械工程师、面料设计师诞生,纺织品产量提升百倍2007年苹果开放&nbsp;App&nbsp;Store,&quot;移动端开发者&quot;这个职业压根不存在。八年后,全球应用经济规模突破&nbsp;1000亿美元,凭空诞生了数百万开发者岗位。每一次&quot;这次真的完了...
二十岁的编程男神王大...:那这个时代是什么时代呢? 是全员agent的时代,是前端+AI,后端+AI的时代,AI已经融入了项目生命周期的的每一个角落,那我最近在做的东西举例,检查BUG时,我们会用codex,CC等工具的skill去check,效果好还能直接fix,测试的时候,apifox等工具已经有了AI落地的改造,CI/CD阶段,我们会根据hook去跑AI check脚本,就连不少中间件,也迎来了AI落地的改造,(AI网关,AI在MQ中的运用),都可以去了解下 另外记着,这些东西不是意义,工作只是谋生的一个手段,ai是让开发提效了,但是呢,原先一周的工作流程压缩到了两天内,同时低级的都裁员了,只有高级的去维护,你看似写的大义凛然,或许那天你也会成为你文章里面拒绝往前走的人,你才大二,面对技术有热情是对的
AI求职实录
点赞 评论 收藏
分享
评论
8
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务