loj#6277. 数列分块入门 1
#6277. 数列分块入门 1
题目:传送门
简要题意:
对于一个长度为n的数列进行区间加法修改和单点询问。
题解:
做分块的题需要一定的知识基础,这里就不一一讲解了,主要讲应用到每道题目是的具体做法:
对于单点询问相对比较简单,数组简单存储之后就可以O(1)输出。
主要就是对于区间修改:
分块之后,对于需要修改的L~R的区间,可以简单分情况讨论:
1、如果l和r同属一块,那么直接枚举修改
2、如果不属于同一块,那么先将左端点所属的块从L开始到该块结尾修改,再将右端点所属的块从该块开头到R修改
然后就是修改中间没有涉及到的块了,其实也是直接暴力,用一个新的数组统计该块整块都增加的值,枚举L的下一个块到R的上一个块就OK
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 int n,a[51000],ba[51000]; 8 int block,pos[51000]; 9 void update(int l,int r,int c) 10 { 11 for(int i=l;i<=min(pos[l]*block,r);i++)a[i]+=c; 12 if(pos[l]!=pos[r]) 13 for(int i=(pos[r]-1)*block+1;i<=r;i++) 14 a[i]+=c; 15 for(int i=pos[l]+1;i<=pos[r]-1;i++)ba[i]+=c; 16 } 17 int main() 18 { 19 scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]); 20 block=sqrt(n); 21 for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1; 22 for(int i=1;i<=n;i++) 23 { 24 int l,r,c,opt; 25 scanf("%d%d%d%d",&opt,&l,&r,&c); 26 if(opt==0)update(l,r,c); 27 else printf("%d\n",a[r]+ba[pos[r]]); 28 } 29 return 0; 30 }