数列分块入门1(区间加法)

原题:http://www.caioj.cn/problem.php?id=1244

题解:对于区间[l,r]的所有元素加c并要求单点的值。显然可以用线段树来求,但本篇要用新的方法来求。

令:m为每一个块的大小,且m为根号n向下取整。每个块大小为m,共有n/m个块由于每次不完整的块大小较少,即每次操作时间复杂度为O(m+\frac{n}{m})。又因m*\frac{n}{m}=n根据均值不等式当m=\frac{n}{m}时时间复杂度最少。所以每个块的大小为:m=\sqrt{n}

规定:

m=sqrt(n)//每个块的大小
pos[i] //i是第几个块
sum[i] //第i个块的标记

 

对于每一组操作,先暴力处理两边的块,在个中间的块打上标记。答案就是a[i]+sum[pos[i]]

#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 110000
using namespace std;
int a[N],pos[N],sum[N];
int n,m,l,r,c,opt;
inline void add(int l,int r,int c){
	for(int i=l;i<=min(r,pos[l]*m);i++) a[i]+=c;
	if(pos[l]!=pos[r])
		for(int i=(pos[r]-1)*m+1;i<=r;i++) a[i]+=c;
	for(int i=pos[l]+1;i<=pos[r]-1;i++) sum[i]+=c;
}
int main(){
//	freopen("input.in","r",stdin);
	scanf("%d",&n);m=sqrt(n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),pos[i]=(i-1)/m+1; 
	for(int i=1;i<=n;i++){
		scanf("%d%d%d%d",&opt,&l,&r,&c);
		if(opt==1) printf("%d\n",a[r]+sum[pos[r]]);
		else add(l,r,c);
	}
	return 0;
}

 

 

posted @ 2018-12-23 22:36  Exception2017  阅读(207)  评论(0编辑  收藏  举报