LOJ 6277:数列分块入门 1(分块入门)

#6277. 数列分块入门 1

内存限制:256 MiB时间限制:100 ms标准输入输出

题目类型:传统评测方式:文本比较

上传者: hzwer

提交提交记录统计讨论

3

测试数据

题目描述

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

输入格式

第一行输入一个数字 n。

第二行输入 n 个数字,第 i 个数字为 ai,以空格隔开。

接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。

若 opt=0,表示将位于 [l,r]的之间的数字都加 c。

若 opt=1,表示询问 ar 的值(l 和 c 忽略)。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0

样例输出

2
5

数据范围与提示

对于100% 的数据,1≤n≤50000,−2^31≤others 、ans≤2^31−1。

思路

有好多种写法,因为在学分块,就用分块来写了

将长度为n的数组进行分块,每个块的长度len=sqrt(n),块数为n/len

每次需要更新时,判断需要更新的区间的左右端点是不是在一个块内,如果在一个块内,直接对这个区间进行更新就好了

如果不在一个块内,从左端点开始到左端点所在的块的最后一个元素进行数组元素的更新,然后从右端点所在块的第一个元素开始到右端点进行数组元素的更新,对于中间的那些块,用tag数组记录下这个块中的元素一共加了多少

最后输出的时候输出当前元素的值加上该元素所在块的tag值就行了

AC代码

/*
* @Author: WZY
* @School: HPU
* @Date:   2018-10-11 17:08:19
* @Last Modified by:   WZY
* @Last Modified time: 2018-10-11 19:32:23
*/
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <limits.h>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <string>
#include <time.h>
#define ll long long
#define ull unsigned long long
#define ms(a,b) memset(a,b,sizeof(a))
#define pi acos(-1.0)
#define INF 0x7f7f7f7f
#define lson o<<1
#define rson o<<1|1
#define bug cout<<"---------"<<endl
#define debug(...) cerr<<"["<<#__VA_ARGS__"= "<<(__VA_ARGS__)<<" ]"<<"
"
const double E=exp(1);
const int maxn=1e6+10;
const int mod=1e9+7;
using namespace std;
int a[maxn];
int blo[maxn];
int tag[maxn];
int block;
inline void add(int l,int r,int c)
{
	// 对端点l到端点l所在块的终点进行操作
	for(int i=l;i<=min(blo[l]*block,r);i++)
		a[i]+=c;
	// 如果左右端点不在一个块内,从右端点所在的块的起点到右端点进行操作
	if(blo[l]!=blo[r])
		for(int i=(blo[r]-1)*block+1;i<=r;i++)
			a[i]+=c;
	// 对中间的块用tag数组标记每个块内元素增加了多少
	for(int i=blo[l]+1;i<=blo[r]-1;i++)
		tag[i]+=c;
}
int main(int argc, char const *argv[])
{ 
	ios::sync_with_stdio(false);
	#ifndef ONLINE_JUDGE
	    freopen("in.txt", "r", stdin);
	    freopen("out.txt", "w", stdout);
	    double _begin_time = clock();
	#endif
	int n;
	int opt,l,r,c;
	cin>>n;
	// 每个块的长度为sqrt(n)
	block=sqrt(n);
	for(int i=1;i<=n;i++)
		cin>>a[i];
	// 计算下标1~n属于哪个块
	for(int i=1;i<=n;i++)
		blo[i]=(i-1)/block+1;
	for(int i=1;i<=n;i++)
	{
		cin>>opt>>l>>r>>c;
		if(opt)
			cout<<a[r]+tag[blo[r]]<<endl;
		else
			add(l,r,c);
	}
	#ifndef ONLINE_JUDGE
	    double _end_time = clock();
	    printf("time = %lf ms.", _end_time - _begin_time);
	#endif
	return 0;
}
原文地址:https://www.cnblogs.com/Friends-A/p/10324342.html