P3368 【模板】树状数组 2 (树状数组维护差分数组)

题目连接: 【模板】树状数组 2
写这个题是打算学习差分的,所以就没写线段树和树状数组。

差分

来自: Snitro

设 数 组 a [   ] = { 1 , 6 , 8 , 5 , 10 } , 那 么 差 分 数 组 b [   ] = { 1 , 5 , 2 , − 3 , 5 } 设数组a[\ ]=\{1,6,8,5,10\},那么差分数组b[\ ]=\{1,5,2,-3,5\} a[ ]={1,6,8,5,10}b[ ]={1,5,2,3,5}

也 就 是 说 b [ i ] = a [ i ] − a [ i − 1 ] ( a [ 0 ] = 0 ) , 那 么 a [ i ] = b [ 1 ] + . . . . + b [ i ] 也就是说b[i]=a[i]-a[i-1] (a[0]=0),那么a[i]=b[1]+....+b[i] b[i]=a[i]a[i1](a[0]=0),a[i]=b[1]+....+b[i](这个很好证的)。

假 如 区 间 [ 2 , 4 ] 都 加 上 2 的 话 假如区间[2,4]都加上2的话 [2,4]2

a 数 组 变 为 a [   ] = { 1 , 8 , 10 , 7 , 10 } , b 数 组 变 为 b [   ] = { 1 , 7 , 2 , − 3 , 3 } ; a数组变为a[\ ]=\{1,8,10,7,10\},b数组变为b[\ ]=\{1,7,2,-3,3\}; aa[ ]={1,8,10,7,10}bb[ ]={1,7,2,3,3};

发 现 了 没 有 , b 数 组 只 有 b [ 2 ] 和 b [ 5 ] 变 了 , 因 为 区 间 [ 2 , 4 ] 是 同 时 加 上 2 的 , 所 以 在 区 间 内 b [ i ] − b [ i − 1 ] 是 不 变 的 . 发现了没有,b数组只有b[2]和b[5]变了,因为区间[2,4]是同时加上2的,所以在区间内b[i]-b[i-1]是不变的. bb[2]b[5][2,4]2,b[i]b[i1].

所 以 对 区 间 [ x , y ] 进 行 修 改 , 只 用 修 改 b [ x ] 与 b [ y + 1 ] : 所以对区间[x,y]进行修改,只用修改b[x]与b[y+1]: [x,y],b[x]b[y+1]:

b [ x ] = b [ x ] + k ; b [ y + 1 ] = b [ y + 1 ] − k ; b[x]=b[x]+k;b[y+1]=b[y+1]-k; b[x]=b[x]+k;b[y+1]=b[y+1]k;

然后我照着写了一发 T 了。。。
然后又看到下面有人用树状数组维护差分数组

AC code
/*
【模板】树状数组 2
P3368
https://www.luogu.org/problem/P3368
解法: 树状数组维护差分数组
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 1000000
ll a[maxn];
ll tree[maxn<<1];
ll n,m;
inline long long read()//快读
{
    long long x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-48;c=getchar();}
    return x*f;
}
void update(int x,int val){
	while(x<=n){
		tree[x]+=val;
		x+=x&(-x);
	}
}
long long sum(long long x){
	long long ans=0;
	while(x>=1){
		ans+=tree[x];
		x-=x&(-x);
	}
	return ans;
}
int main(){
  int s,l,r,x;
  n=read();
  m=read();
  memset(tree,0,(n+1)*sizeof (ll));
  for(int i=1;i<=n;i++){
    a[i]=read();
    update(i,a[i]-a[i-1]);
  }
  while(m--){
    s=read();
    if(s==2){
      x=read();
      printf("%lld\n", sum(x));
    }else{
      l=read();
      r=read();
      x=read();
      update(l,x);
      update(r+1,-x);
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值