区间加法,单点求值。html
数列分块是个好东西。。。我这里详细介绍一下分块算法,便于初学者的理解(我这个蒟蒻原来也是看不懂分块)。算法
先把数组分红几个块块,而后就能够对它们总体操做啦。数组
也就是说,把一个长度为的数组,拆分红一个个长度为sqrt(n)小块(固然,最后一块可能不完整,可是不用管),记录每一个数所属的块;也就是这样——(方便起见,咱们直接再开一个数组来记录所属分块,虽然本题中能够临时计算,但在有些题目中这一步显得尤其重要)spa
scanf( "%d", &n ); m = (int)sqrt(n); for ( int i = 1; i <= n; ++i ) p[i] = ( i - 1 ) / m + 1; for ( int i = 1; i <= n; ++i ) scanf( "%d", &a[i] );
而后,就能够瞎暴力辣!code
实际上,全部的分块都是这样。把一个数列分红几块,而后对它们进行批量处理。通常来讲,咱们直接把块大小设为sqrt(n),但实际上,有时候咱们要根据数据范围、具体复杂度来肯定。htm
当有修改时,对于完整的块,直接维护一个数组v记录整个块加过的数(每块共同的加数),不完整的就直接暴力在原数组a上直接加。询问时,直接输出原数组的值+所属块的共同加数便可。blog
#include<cstdio> #include<cmath> using namespace std; #define MAXN 50005 int n, a[MAXN], p[MAXN], m, v[300]; int opt, l, r, c; void Add( int l, int r, int c ){ if ( p[l] == p[r] ){//同属一分块时直接暴力便可 for ( int i = l; i <= r; ++i ) a[i] += c; return; } for ( int i = l; p[i] == p[l]; ++i ) a[i] += c;//对于两边不完整(即便完整也无论,看作不完整)的分块,直接暴力便可 for ( int i = r; p[i] == p[r]; --i ) a[i] += c; for ( int i = p[l] + 1; i <= p[r] - 1; ++i ) v[i] += c;//记录完整分块的共同加数 } int main(){ scanf( "%d", &n ); m = (int)sqrt(n); for ( int i = 1; i <= n; ++i ) p[i] = ( i - 1 ) / m + 1;//记录所属分块 for ( int i = 1; i <= n; ++i ) scanf( "%d", &a[i] ); for ( int i = 1; i <= n; ++i ){ scanf( "%d%d%d%d", &opt, &l, &r, &c ); if ( opt == 0 ) Add( l, r, c ); else printf( "%d\n", v[p[r]] + a[r] );//所属分块共同加数+原数组的值 } return 0; }
分块代码能够比线段树简洁很多,虽然暴力但十分巧妙,并且十分灵活,适用于更多的题目。get
可是若是时间复杂度要求较高,分块的O(n sqrt(n))就不能承受了,因此仍是要学会乖乖打线段树QAQ。io
数列分块入门1 <-入门