分块【线段树模板】

线段树的一些操作其实用分块也可以很方便就做掉,至于时间效率也不会慢很多,主要是好写

对于区间加法一样用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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值