浅谈块状链表 + 例题

本文介绍了块状链表这种数据结构,它结合了分块和链表的优点,适用于大规模区间操作和单点插入删除。文章阐述了块状链表的思想,包括如何维护数据的稳定性和分裂过程,并通过Luogu的普通平衡树模板展示了其实现。最后提供了代码示例和Loj数列分块入门6的题目应用。
摘要由CSDN通过智能技术生成

本文来自我的博客 块状链表详解 + 例题

引入

块状链表,顾名思义,就是把分块和链表结合起来的神奇数据结构。

  • 分块区间操作复杂度优秀,但是不能支持 插入/删除 操作。

  • 链表单点插入删除复杂度优秀,但是不能支持大规模的区间操作。

但是两者相结合,就会变得非常无敌。

块状链表思想

块状链表的实现原理根本上就是保证每个块的大小稳定在 n \sqrt{n} n 级别,从而保证块数也为根号级别。但是插入数据之后,可能会出现某个快过大的情况。当块长 > 2 n > 2 \sqrt{n} >2n 时,可以将块分裂成两个,保证每块大小稳定在 [ n , 2 n ] [\sqrt{n}, 2\sqrt{n}] [n ,2n ]。这样分裂的复杂度是单根号的。

这样保证了块数为根号级别,定位一个数的位置也可以在 O ( n ) O(\sqrt n) O(n ) 复杂度内解决。只要能定位数所在的位置,就可以用 O ( 1 ) O(1) O(1) 复杂度完成插入和删除,其他操作都跟分块复杂度相同。

块状链表如何维护数据

Luogu 普通平衡树模板 做例题。

要支持在 O ( n ) O(\sqrt n) O(n ) 复杂度内维护一个有序序列。

首先需要建一个双链表(某些题可以单链表),作为外层数据结构。

然后再每个链表里面维护一个小链表(可以用 vector 实现),来维护当前块。另外,由于后续操作写成 (p -> vector).lower_bound((p -> vector).begin(), (p -> vector).end(), x) 这样的形式不是很美观,也可以在块链类内部提前封装类似函数。

  • 块状链表定义形式

struct node {
    // 构建块状链表类
    node *next, *pre;
    vector<int> v;
    node() {
    next = pre = NULL; }
    void insert(int x) {
    v.emplace_back(x); }
    int vsize() {
    return v.size(); }
    int back() {
    return v[v.size() - 1]; }
    int front() {
    return v[0]; }
    vector<int>::iterator vbegin() {
    return v.begin(); }
    vector<int>::iterator vend() {
    return v.end(); }
    vector<int>::iterator lower(int x) {
    return lower_bound(v.begin(), v.end(), x); }
    vector<int>::iterator upper(int x) {
    return upper_bound(v.begin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值