线段树的一些操作其实用分块也可以很方便就做掉,至于时间效率也不会慢很多,主要是好写
对于区间加法一样用lazy数组标记,如果区间覆盖整块,则把块给标记上,否则暴力加减,维护sum和lazy数组
#include "cmath"
#include "cstdio"
#include "cstdlib"
#include "cstring"
#include "iostream"
#include "algorithm"
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define rep(i,a,b) for(i=(a);i>=(b);--i)
#define mm(a,b) memset(a,b,sizeof(a))
#define ll long long
#define inf 999999999
using namespace std;
ll read(){
ll sum = 0,fg = 1;char c = getchar();
while(c < '0' || c > '9'){if (c == '-')fg = -1; c = getchar(); }
while(c >='0' && c <='9')sum = sum*10 + c-'0',c = getchar();
return sum*fg;
}
const int maxn = 100010;
ll sum[maxn];
int n , m ;
int block[maxn] ;
ll a[maxn] ;
int blo ;
ll lazy[maxn];
void add(int x,int y,int k){
int i;
int bloa = block[x] , blob = block[y];
int tmp = min(bloa * blo , y);
For(i, x ,tmp){
a[i] += k;sum[bloa] += k;
}
if(bloa != blob){
tmp = (blob - 1) * blo + 1;
For(i ,tmp , y){
a[i] += k;sum[blob] += k;
}
}
For(i , bloa+1 , blob-1){
lazy[i] += k;
}
}
ll query(int x,int y){
int bloa = block[x], blob = block[y];
int i;
int tmp = min(bloa * blo, y) ;
ll ans = 0;
For(i, x, tmp){
ans += a[i] + lazy[bloa];
}
if(bloa != blob){
tmp = (blob - 1) * blo + 1;
For(i ,tmp , y){
ans += a[i] + lazy[blob];
}
}
For(i ,bloa+1, blob-1){
ans += blo * lazy[i] + sum[i];
}
return ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("THUNDER.in","r",stdin);
freopen("THUNDER.out","w",stdout);
#endif
int i,j;
scanf("%d%d",&n,&m);blo = sqrt(n);
For(i ,1 ,n){
a[i] = read();
block[i] = (i - 1) / blo + 1;
sum[block[i]] += a[i];
}
int x,y,k,type;
For(j, 1, m){
scanf("%d",&type);
if(type == 1){
scanf("%d%d%d",&x,&y,&k);
add(x , y , k);
}
else{
scanf("%d%d",&x,&y);
printf("%lld\n",query(x , y));
}
}
return 0;
}
//THE END