分块
数列分块
其实,分块是一种思想,而不是一种数据结构。——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\) 的元素个数。
思路

浙公网安备 33010602011771号