线段树的一些操作其实用分块也可以很方便就做掉,至于时间效率也不会慢很多,主要是好写
对于区间加法一样用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