| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 题解 [COCI2010-2011#7] UPIT -> 正文阅读 |
|
[数据结构与算法]题解 [COCI2010-2011#7] UPIT |
题解做法:块状链表。 若只有 1、2、4 操作,即题目 P1438 无聊的数列,可以用线段树 + 差分轻松维护,也可以用分块实现,这两种做法都是在线的。 新增一个 3 操作,用线段树难以在线实现插入操作,只能离线实现。如果强制在线呢?我们考虑用分块来实现。 操作 1:区间赋值。 散块暴力修改,整块用一个数组 操作 2:区间加等差数列。 这个等差数列比较特别,它的首项等于公差。如果有个整块一直是进行操作 1 和 2 的,那么整块中的相邻两个元素差是固定的,即最后一次操作 1 后的所有操作 2 对应的公差之和。因此,我们记下公差之和,以及整块中第一个元素值的增量。 操作 3:单点插入。 找到插入点对应的块,如果插入点等于当前序列长度 +1,则归为最后一块。类似暴力,将插入点后所有元素全部后移,然后填上插入的元素。用 vector 可以实现,但常数较大。正因这一部分,我使用了块状链表。 注意插入点后所有元素全部后移只能在该块内实现,若全部更新复杂度无法接受。因此我们对链表上每个元素记录它的原编号(即按输入以及插入顺序),并记录它在当前块中的排名(从前往后数第几个),在进行操作时直接遍历当前块对应链表,将符合修改目的的元素进行修改即可。 考虑极端情况:几乎所有插入全部插入在同一点,那么单块最长可达 block + m \text{block}+m block+m。若所有查询都是求序列元素总和,则统计上述情况块时的复杂度不再为 O ( block ) O(\text{block}) O(block),而是达到了 O ( block + m ) O(\text{block}+m) O(block+m)。上述两种极端操作均匀出现,忽略常数,则总复杂度最高可达 O ( ( block + m ) 2 ) O\big((\text{block}+m)^2\big) O((block+m)2),无法承受。因此当存在一个整块大小超过 2 × block 2\times \text{block} 2×block 时,我们需要重构,那么最多重构 m / block m/\text{block} m/block 次。 注意:插入前需要下传标记,插入后若重构,需要重新统计每块大小。 操作 4:区间求和。 这个操作就非常 naive 了,仍需注意的是统计前下传标记。 认为 n n n 和 m m m 同阶,取 block = n + m \text{block}=\sqrt{n+m} block=n+m? 左右时,总时间复杂度约为 O ( n n ) O(n\sqrt{n}) O(nn?)。 如果您通过上述文字尚无法理解或不清楚如何实现,可以点击下面链接具体了解。 其中展示的代码使用语言 C++14 提交,可以在不开启 O2 优化的情况下通过。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 22:49:25- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |