分块

数列分块

其实,分块是一种思想,而不是一种数据结构。——OI-wiki

分块的基本思想是,通过对原数据的适当划分,并在划分后的每一个块上预处理部分信息,从而较一般的暴力算法取得更优的时间复杂度。

分块的时间复杂度主要取决于分块的块长,快长一般取 \(\sqrt{n}\) 时,时间复杂度时最优的。

P13976 数列分块入门 1

题意简化:

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,单点查值。

思路:

很板很板的分块板子

每次修改操作对完整的块打上标记,对于不完整的直接暴力修改。因为每个块的块长不超过 \(\sqrt{n}\),所以单次区间修改的复杂度为 \(O(\sqrt{n})\)

查询时只需要将当前位置的值 + 标记的值就可以了,故单点查询的复杂度为 \(O(1)\)

总时间复杂度为 \(O(n\sqrt{n})\)

注意开longlong

code:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int QWQ = 3e5 + 5;
int n, m, a[QWQ], tag[QWQ], block, col[QWQ], num;
struct node
{
    int l, r;
}b[QWQ];
void update(int l, int r, int c)
{
    if(col[l] == col[r])
    {
        for(int i = l;i <= r;i ++)
        {
            a[i] += c;
        }
        return ;
    }
    for(int i = l; i <= b[col[l]].r; i++)
    {
        a[i] += c;
    }
    for(int i = b[col[r]].l; i <= r; i++)
    {
        a[i] += c;
    }
    for(int i = col[l] + 1; i < col[r]; i++)
    {
        tag[i] += c;
    }
}
signed main()
{
    cin >> n;
    block = sqrt(n);
    num = n / block;
    if(n % block != 0)num ++;
    for(int i = 1;i <= n;i ++)
    {
        cin >> a[i];
        col[i] = (i - 1) / block + 1;
    }	
    for(int i = 1;i <= num;i ++)
    {
        b[i].l = block * (i - 1) + 1;
        b[i].r = min(block * i, n);
    }
    b[num].r = n;
    while(n --)
    {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 0)
        {
            update(l, r, c);
        }
        if(op == 1)
        {
            cout << a[r] + tag[col[r]] << endl;
        }
    }
}


P13977 数列分块入门 2

题意:

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的元素个数。

思路

posted @ 2025-10-17 09:14  FurinaQWQ  阅读(7)  评论(0)    收藏  举报