洛谷P2342叠积木解题报告

本文详细介绍了洛谷P2342叠积木问题的解题思路,通过加权并查集算法高效解决栈合并及查询高度的操作。文章深入解析了并查集的维护技巧,包括栈顶元素、高度计数和父节点更新,并对比了递归与循环在找父亲过程中的性能与灵活性。

叠积木

洛谷P2342


技术统计

难度 提高+/省选-

用时 30min

提交次数 3

unaccept 次数 1

ac次数 2


题意概括

我们首先将所有的积木想象为一个一个的栈,要求我们维护一下个操作

  1. 将两个栈合并
  2. 查询i号点在其所在的栈的高度( 到栈底有多少个元素 )

数据范围

1 &lt; = p &lt; = 1 0 5 1&lt;=p&lt;=10^5 1<=p<=105



解法、

知识点

  1. 并查集
  2. 加权并查集(嘤)

解法概括

用三个数组:head[ i ],cnt[ i ],fa[ i ],分别维护i号点所在的栈的栈顶元素、i号点到栈底的高度、i号点所在的栈的栈底元素。我们设i号点所在的栈为栈A,j号点(请先不要疑惑j号点是哪里来的,这其实就是设了一个未知数)所在的栈的为栈B。

head[i]的更新

当我们将栈A放在栈B上面的时候,显然栈A的栈顶变为栈B的栈顶,所以head[j]=head[i]。

cnt[i]的更新

我们使用一种类似于线段树中懒标记的思想:用的时候再更新。
但是我们不可能重新开其他数组记录所有的合并信息(好像可以,但会很浪费空间),所以我们就先只更新原来栈A的栈底k,让cnt[k]=cnt[head[j]]+1,等询问到的时候,我们用find函数找爸爸的特性来更新。

fa[i]的更新… …

就是普通并查集的更新了啊

坑点

  1. 在维护点x到栈底的距离的时候,可以在find函数中修改,但一定要加cnt[head[y]]
  2. 其实没必要维护一个sum[i]来记录以i为栈底的栈的大小,显然cnt[head[i]]==sum[i]
  3. 这里提一下用递归找父亲和while找父亲的区别:
    一般while会跑得更快一些(实测,也可能是我的递归版本太渣),但是相对于递归版本,个人认为while不如递归版本灵活,我在打加权并查集的时候一般都用递归。

代码实现

#include<bits/stdc++.h>
#define maxn 30010
using namespace std;
int n;
int head[maxn],cnt[maxn],fa[maxn];
int find(int a)
{
    if(a==fa[a])return a;
    else 
    {
        int fat=fa[a];
        fa[a]=find(fat);
        cnt[a]+=cnt[fat];
        head[a]=head[fat];
        return fa[a];
    }
}
void merge(int x,int y)
{
    fa[x]=y;
    find(head[y]);
    cnt[x]=cnt[head[y]]+1;
    head[y]=head[x];
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    for(int i=1;i<=maxn;i++)fa[i]=head[i]=i;
    for(int i=1;i<=n;i++)
    {
        char a;
        int x,y;
        cin>>a;
        if(a=='M')
        {
            cin>>x>>y;
            int fx=find(x),fy=find(y);
            if(fx!=fy) merge(fx,fy);
        }
        else 
        {
            cin>>x;
            find(x);
            cout<<cnt[x]<<endl;
        }
    }
    return 0;
}


类似题目

  1. 银河英雄传说(就是一个题)
  2. How Many Answers Are Wrong
### 贪心算法与发散级数在积木问题中的应用 #### 贪心算法概述 贪心算法是一种用于解决最优化问题的方法,在每一步选择中都采取当前状态下最好或者最优的选择,从而希望导致结果是全局最优的解决方案[^1]。 对于某些特定类型的组优化问题而言,这种策略能够有效地找到近似解甚至是精确解。然而值得注意的是,并不是所有的最优化问题都可以通过简单的贪婪方法来求得最佳解答;因此理解何时以及如何正确运用该技术至关重要。 #### 发散级数的概念及其特性 发散级数是指那些部分和序列不收敛于有限极限值的一系列项之和。这类数学对象通常不具备传统意义上的数值意义,但在理论物理等领域有着特殊用途。当讨论到实际计算或工程实践时,则往往需要考虑其截断误差所带来的影响。 #### 积木问题描述 假设有一组不同尺寸大小各异但形状规则(比如矩形)的小方块作为构建材料,目标是在遵循一定规则的前提下尽可能高效率地堆砌这些组件形成稳定结构——即所谓的“积木”。 此过程可以被建模成一个多阶段决策流程: - **输入数据**:一系列具有宽度w_i, 高度h_i 和长度l_i 的长方体。 - **约束条件**:任意两个相邻层之间必须满足稳定性要求,例如上一层投影面积完全覆盖下一层等几何关系。 - **评价标准**:最大化最终塔的高度H 或者最小化所使用的总数量N。 #### 应用场景分析 针对上述定义下的积木挑战,采用基于贪心原则的设计思路确实可行。具体来说就是每一次迭代过程中总是挑选那个能够在保持整体平衡的同时增加最大高度增量的那个箱子放置上去直到不能再继续为止[^2]。 不过需要注意的是这种方法并不能保证一定能获得绝对意义上最好的答案因为存在反例证明单纯依靠局部极值未必能导向全局最优解。此外如果引入更多复杂因素像旋转自由度或是重心偏移限制那么情况将会变得更加棘手此时或许就需要借助动态规划或者其他更高级别的寻优手段来进行处理了。 ```python def greedy_stack(boxes): boxes.sort(key=lambda box: (box[0], -box[1]), reverse=True) # Sort by width then height descending stack = [] for w, h in boxes: placed = False while not placed and stack: top_w, _ = stack[-1] if w <= top_w: # Can place on top of current top block? stack.append((w,h)) placed = True if not placed: # If no suitable position found add as new base layer. stack.insert(0,(w,h)) return sum([height for _, height in stack]) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值