分块与块状链表

分块与块状链表

1. 算法分析

1.1 分块思想

分块思想就是将整体分为 n \sqrt n n 个长度为 n \sqrt n n 的区间,这样区间修改和查询的复杂度从 O ( n ) O(n) O(n)降为了 O ( n ) O(\sqrt n) O(n )

维护两个数组:add代表本段中的所有数都要加上add,sum代表本段的真实和是多少(算上了add)

修改一个区间时,分为完整段的区间修改以及前后两个不完整的段的区间修改:

对于完整段,add+=d,sum+=d*length

对于不完整的段:枚举所有元素,a+=d,sum+=d

查询时,对于完整段,累加sum,对于不完整的段,枚举元素

1.2 块状链表

如果操作需要进行插入、删除的操作的话,原来的分块就不适用了。因此引入了块状链表。块状链表就是将分块与链表加在一起,使用链表来维护不同分块之间的关系。

具体分为如下操作:

  1. 插入一段:(1) 分裂结点 O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n)) (2) 在分裂点插入序列 O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n))
  2. 删除一段:(1) 删除开头结点的后半部分 O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n)) (2) 删除中间的完整结点 O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n)) (3) 删除结尾结点的前半部分 O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n))
  3. 合并:遍历整个链表,若下一个点可以合并到到当前结点,则合并。 O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n))

其中,合并操作不需要每次都进行,可以设定一个阈值进行,比如:当分块的数目为 O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n)) 时进行合并。

基本上块状链表的题目都可以使用splay来写,基本上可以互通

2. 板子

2.1 分块

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N = 100010, M = 350;

int n, m, len;
LL add[M], sum[M];  // add[i]表示第i块还需要加的值,sum[i]为第i块的权值和
int w[N];

int get(int i) {
    return i / len; }

void change(int l, int r, int d) {
   
    if (get(l) == get(r)) {
     // 段内直接暴力
        for (int i = l; i <= r; i++) w[i] += d, sum[get(i)] += d;
    } else {
   
        int i = l, j = r;
        while (get(i) == get(l)) w[i] += d, sum[get(i)] += d, i++;
        while (get(j) == get(r)) w[j] += d, sum[get(j)] += d, j--;
        for (int k = get(i); k <= get(j); k++) sum[k] += len * d, add[k] += d;  // 每一段的操作
    }
}

LL query(int l, int r) {
   
    LL res = 0;
    if (get(l) == get(r)) {
     // 段内直接暴力
        for (int i = l; i <= r; i++) res += w[i] + add[get(i)];
    } else {
   
        int i = l, j = r;
        while (get(i) == get(l)) res += w[i]
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值