zoukankan      html  css  js  c++  java
  • 洛谷 P2342 叠积木 题解

    本蒟蒻又来发题解了

    这题是不是有点像并查集,但是那个询问的个数是不是有点骚;

    所以,普通的并查集是无法解决这个问题的,这个时候就需要用到带权并查集了;

    每次跑的时候都记录下它的下面有几个点,然后询问的时候的复杂度是O(1)的;

    好,接下来就可以愉快的码代码了:

    #include<bits/stdc++.h>
    using namespace std;
    
    #define maxn 500010
    char ch;
    int n, x, y, fa[maxn], sum[maxn], num[maxn];
    
    //比常规的并查集多了一行 
    int find(int x)
    {
        if(fa[x] == x)
            return x;
        sum[x] += sum[fa[x]];//还需要统计它下面的积木数 
        return fa[x] = find(fa[x]);
    }
    
    //fa[]就不说了,sum[]是来存它下面的积木数,num[]是这一列的积木数; 
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= maxn; ++ i)
        {
            fa[i] = i;//嗯,它的祖先就是它自己,常规操作; 
            sum[i] = 0;//它的下面QwQ肯定没有积木啊 
            num[i] = 1;//目前这一列只有一个积木 
        }
        for(int i = 1; i <= n; ++ i)
        {
            cin >> ch;
            if(ch == 'M')//如果这是'M',那就要合并
            {
                scanf("%d%d", &x, &y);
                x = find(x), y = find(y);
                if(x != y)//如果他们的祖先不同,就是他们不在同一个联通块上 
                {
                    fa[x] = y;//合并它们 
                    sum[x] = num[y]; //数量要相加
                    num[y] += num[x]; //因为x要和y合并
                }
            }
            else
            {
                scanf("%d", &x);
                find(x);//还需要再来一次;
                printf("%d
    ", sum[x]);//O(1)输出; 
            }
        }
        return 0;
    }
    

    嗯,你愉快的拿了27分;

    好,开始查错了,

    戴上眼镜,睁大眼睛

    哪里有错?

    就是过不去数据,哎;

    好吧,我猜这么神仙的你们肯定找到哪里错了,不像蒟蒻我(划掉

    #include<bits/stdc++.h>
    using namespace std;
    
    #define maxn 500010
    char ch;
    int n, x, y, fa[maxn], sum[maxn], num[maxn];
    //fa[]就不说了,sum[]是来存它下面的积木数,num[]是这一列的积木数; 
    
    //比常规的并查集多了一行 
    int find(int x)
    {
        if(fa[x] == x)
            return x;
        int f = find(fa[x]);
        sum[x] += sum[fa[x]];//还需要统计它下面的积木数 
        return fa[x] = f;
    }
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= maxn; ++ i)
        {
            fa[i] = i;//嗯,它的祖先就是它自己,常规操作; 
            sum[i] = 0;//它的下面QwQ肯定没有积木啊 
            num[i] = 1;//目前这一列只有一个积木 
        }
        for(int i = 1; i <= n; ++ i)
        {
            cin >> ch;
            if(ch == 'M')//如果这是'M',那就要合并
            {
                scanf("%d%d", &x, &y);
                x = find(x), y = find(y);
                if(x != y)//如果他们的祖先不同,就是他们不在同一个联通块上 
                {
                    fa[x] = y;//合并它们 
                    sum[x] = num[y]; //数量要相加
                    num[y] += num[x]; //因为x要和y合并
                }
            }
            else
            {
                scanf("%d", &x);
                find(x);//还需要再来一次;
                printf("%d
    ", sum[x]);//O(1)输出; 
            }
        }
        return 0;
    }
    

    有没有发现哪里错了,

    是的,就是在find函数里面;

    第一个代码是:

    int find(int x)
    {
        if(fa[x] == x)
            return x;
        sum[x] += sum[fa[x]];//还需要统计它下面的积木数 
        return fa[x] = find(fa[x]);
    }
    

    第二个代码是:

    int find(int x)
    {
        if(fa[x] == x)
            return x;
        int f = find(fa[x]);
        sum[x] += sum[fa[x]];//还需要统计它下面的积木数 
        return fa[x] = f;
    }
    

    是吧,第一个是先更新sum[],再递归;

    而第二个是先递归,再更新sum[];

    所以,我们应该是要先递归完,再来更新;

    如果要先更新的话,那这个find函数对与sum[]的更新就没有作用;

    嗯,就这么结束了;

    PS. AC的代码是第二篇,第一篇有问题;

  • 相关阅读:
    nproc 查看系统可用处理单元数
    c++内存泄露的坑
    内存泄露脚本
    c++内存问题(转)
    tmp
    kprobe
    内存对齐算法
    正则
    P3261 [JLOI2015]城池攻占有趣的做法
    CF1620C BAString题解
  • 原文地址:https://www.cnblogs.com/Flash-plus/p/12028312.html
Copyright © 2011-2022 走看看