LOJ 数列分块入门 1

link

分块

优雅的暴力,对于一个数列,他不是一个元素一个元素处理,而是分成若干块,成块成块的处理,以此达到降低时间复杂度的目的。

需要处理的信息

首先,我们需要处理划分的块的大小—block(一般是根号n)、块的数目、每一个元素对应第几块,然后,每一块的左端点和右端点。

需要思考的问题:

  • 完整的块如何处理
  • 不完整的块如何处理
  • 需要预处理什么东西

题解

完整的块:更新:我们用 l z [ i ] lz[i] lz[i]保存第 i i i个块整块都要加上某个数的总和。
不完整的块:更新:直接更新。
查询:返回这个数和这个数所在块的lz的和。

#include 
using namespace std;
const int maxn = 5e4+100;

int a[maxn],block,n,num;
int l[maxn],r[maxn],belong[maxn],lz[maxn];

void init()
{
	block = sqrt(n);
	num = n/block + (n%block != 0);
	for(int i=1;i<=n;i++)belong[i] = (i-1)/block + 1;

	for(int i=1;i<=num;i++)
	{
		l[i] = (i-1)*block + 1;
		r[i] = i*block;
	}
	r[num] = n;
}

void up(int ql,int qr,int c)
{
	if(belong[ql] == belong[qr])
	{
		for(int i=ql;i<=qr;i++)a[i] += c;
		return ;
	}
	for(int i=belong[ql] + 1; i <belong[qr];i++)lz[i] += c;
	for(int i=ql;i<=r[belong[ql]];i++)
		a[i] += c;
	for(int i=l[belong[qr]];i<=qr;i++)
		a[i] += c;
}

int qu(int p)
{
	return a[p] + lz[belong[p]];
}
int main()
{
	cin >> n;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	init();
	for(int i=1;i<=n;i++)
	{
		int op,ql,qr,c;
		cin >> op >> ql >> qr >> c;
		if(op == 1)
		{
			cout<<qu(qr)<<'\n';
		}
		else 
		{
			up(ql,qr,c);
		}
	}
}

你可能感兴趣的:(分块)