2024集训D5总结
集训D5总结
讲课内容
其实主要都是关于数据结构的一些 idea .
函数复合
序列上每一个点都是一个函数 , 要求的是一个值 \(x\) 经过 $L\cdots R $ 的处理后的结果 , 即 \(F_R(F_{R-1}(\cdots F_L(x)))\) .
一种做法是把询问离线 , 用数据结构维护 , 在 \(L\) 处插入 , 每一步对维护的所有值统一操作 , 在 \(R\) 处提取 . 延伸出来 , 还可以考虑做到直接维护函数代表的映射关系 , 以处理在线问题 .
扫描线
比较基础的内容 , 有些内容转化到平面上来思考 . 比如 NOIP t4.
标记永久化
针对树套树的一种想法 . 一般的树套树 , 只能单点修改区间查询 , 其原因是树套树事实上是 DAG 结构 , 一般不支持标记下放 .
因此 , 想到了还有一种 tag 方式 , 即标记永久化 , 首先考虑简单的矩形修改单点查询 :
- 修改时分成了 \(log\) 个区间 , 在每一个区间的内层树上记录修改 , 相当于标记 .
- 单点查询时查询到根的一整条路径上的内层树 .
类似地 , 尝试加入矩形查询 :
- 注意到对答案有影响的区间不只在 \(log\) 个区间到根的路径上 , 还可能在子树内部 , 所以分别讨论 .
- 一个像刚才一样维护跨过这个区间的修改 , 在外层树上到 \(log\) 个节点的路径上查询 .
- 另一个维护子树内所有修改 .
- 分两个内层树处理 , 对于比较难维护的问题 , 也可以都用类似的标记永久化 .
因为标记永久化和树套树都对问题有限制 , 所以能维护的问题也有限 . 重点是后面的分治讨论 .
训练情况
全在刷水题(
QOJ8672 排队
作为函数复合的例题出现 , 不过直接扫过去维护所有答案就可以 . 因为只加 \(1\) , 答案具有显然的单调性 , 这方便了我们把用值域确定的修改位置对应到序列上 , 用树状数组二分 , 常数足够小 , 可以通过 .
CF2042D
扫描线板题 , 但是边界处理很令人烦躁 , 最后选择了用multiset写 , 常数也小 . 在只有求前驱后驱等简单操作时可以选择 stl .
uoj637
有一个比较有趣的转化 , 如果直接维护序列之类发现走不通 , 从单一的数字出发 , 考虑每个数是否能够贡献 , 发现一个数 \(x\) 贡献答案的前提是 :
- 存在 \(x\) 不被区间包含 .
- 存在 \(x-1\) 被区间包含 .
两种情况取或对数据结构来说不好处理 , 用一个经典的存在性转必要性问题 , 考虑一个数不贡献答案 , 要求是以上两个条件取非后的交 . 发现第二条条件可以理解成区间 \(l,r\) 必须是被所有 \(x-1\) 位置分割原序列分割出的若干区间包含的 , 这些区间两两不交 , 因此和条件1取并后的若干的区间也两两不交 , 因此同时研究他们不会有重复的问题 .
问题转化为有 \(O(n)\) 个区间 , 求 \([l,r]\) 被多少区间包含 .
这时平凡的扫描线 , 可以直接树状数组 .
P8264
也是一个函数复合题 , 由于强制在线 , 需要想办法维护区间函数 , 如果维持用平衡树维护函数值 , 可以使用树套树 , 每一部分内用可持久化平衡树处理 .
但是值域 \(1e5\) 显然直接分块就可以 . 考虑如何预处理整块 , 发现就是第二分块 , 直接并查集 .
总结
因为对基本的数据结构的经验已经比较充分了 , 所以想这些题还算流畅 . 而数据结构题真正重要的无非两点 :
- 转化问题到可以数据结构维护 .
- 应用好数据结构 , 解决问题 .
因为数据结构这里以做题为主所以没有太详细写题的分析 , 毕竟思维流程本身还算不是很复杂 , 更以基本功为主 .
后面的大数据结构就要慢慢做了 , 这些题还是很值得一做 , 回头尽可能找出整块时间当 "第一次" 做 .