1 条题解
-
0
题目分析
本题模拟小 E 在动态增加的砖摞上进行搬砖的过程,需要高效处理两种操作:添加新砖摞和查询给定初始精力值下的工作时间。关键观察
- 每次操作时,小 E 会从所有砖摞的顶部同时搬走最多 块砖( 为当前精力值)
- 当一摞砖被完全搬完时,小 E 的精力值会下降该砖摞对应的 值
- 停止条件:
- 没有新的砖摞被完全搬完
- 精力值
- 所有砖已被搬完(但当前小时仍计入工作时间)
算法思路
由于数据规模较大(),需要高效处理:核心思想:分块 + 并查集优化
- 将砖块数量范围 分成 个块
- 每个块维护:
- 该块内砖摞数量的前缀和
- 该块内砖摞总块数的前缀和
- 并查集结构快速找到下一个非空砖摞
状态设计
num[i],sum[i]:原始前缀和数组mkn[i],mks[i]:块级别的懒标记id[i]:从位置 开始的下一个非空砖摞位置mn[i]:块 内的最小非空砖摞位置pa[d][x]:对于步长 ,从 开始的下一个可达位置
操作处理
-
添加操作(op=1)
update(a, b): 更新前缀和数组 num 和 sum 如果 b>0,更新 id 和 mn 数组 更新并查集 pa,维护跳跃指针 -
查询操作(op=2)
初始化 x=0, ans=0 while d > 0: ans++ // 开始新的一小时 if 区间[x+1, x+d]内没有砖块: break if d <= 块大小: 使用并查集快速跳到下一个有砖的位置 计算中间的空闲距离,直接跳过 x += d // 搬砖 d -= 区间[x-d+1, x]内的砖块总重量对应的精力下降
关键优化技巧
-
分块处理
- 将 分成约 300 块
- 块内维护前缀和,块间用懒标记
-
并查集跳跃
- 对于每个可能的步长 ,维护并查集
pa[d][x]表示从 开始,步长为 时下一个有砖的位置
-
快速区间查询
- 使用分块前缀和 查询区间砖块总数
- 使用
id和mn数组 找到下一个非空位置
代码结构
// 数据结构 vector<pi> eg[maxn]; // 邻接表(示例残留,实际未使用) int num[100005], sum[100005]; // 前缀和数组 int mkn[100005], mks[100005]; // 块懒标记 int id[100005], mn[100005]; // 下一个非空位置 int pa[305][100005]; // 并查集跳跃 int st[405], ed[405], bl[100005]; // 分块信息 // 核心函数 void build(): // 初始化分块 void update(x, k): // 添加砖摞 void ins(x): // 更新非空位置信息 int query(d): // 查询工作时间算法正确性
- 基础模拟:严格遵循题目描述的搬砖规则
- 优化等价:跳跃优化不改变实际搬砖顺序,只是跳过无砖区域
- 边界处理:正确处理精力值降为 0、砖块搬完等边界情况
复杂度分析
- 预处理: 初始化并查集
- 添加操作: 更新块信息
- 查询操作:均摊 ,最坏
样例验证
样例1:初始精力3 → 工作3小时
样例2:初始精力4 → 工作4小时
与题目描述完全一致,证明算法正确性。该算法通过分块和并查集的巧妙结合,在大数据规模下高效模拟了搬砖过程,是典型的离线查询优化解决方案。
- 1
信息
- ID
- 4238
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者