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
",a[r]+ba[pos[r]]);
28     }
29     return 0;
30 }
原文地址:https://www.cnblogs.com/CHerish_OI/p/8548715.html