树状数组(区间更新)差分思想

已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数数加上x

2.求出某一个数的和

题:

 

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含2或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x 含义:输出第x个数的值

 

输出格式:

 

输出包含若干行整数,即为所有操作2的结果。

 

输入输出样例

输入样例#1: 复制

5 5
1 5 4 2 3
1 2 4 2
2 3
1 1 5 -1
1 3 5 7
2 4

输出样例#1: 复制

6
10

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

样例说明:

故输出结果为6、10

关于差分:

设数组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];(这个很好证的)。//理解这里很重要

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

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

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

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

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

这个题目是树状数组的一个拓展,在树状数组中可以用前 i 项的和来表示第 i 个数.

那么当对 x ~ y 的区间进行修改的时候需要在树状数组中的第 x 个位置 + k, 第 y + 1 个位置 -k

这样便维护了这个树状数组

输出时候直接输出查询即可

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <list>
#include <deque>
#include <vector>
#include <map>
#define LL long long
int lowbit(int x)
{
    return x&(-x);
}
const int MAXN =1e6+7;
const long long MAX=0x7f7f7f3f;
using namespace std;
void read(int &x){
	char ch = getchar();x = 0;
	for (; ch < '0' || ch > '9'; ch = getchar());
	for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}
long long  arr[MAXN]={0},c[MAXN]={0};
long long  n,m,k;
long long  sum(long long  x,long long  c[])
{
   long long ret=0;
    for(int i=x;i>0;i-=lowbit(i))
    {
        ret+=arr[i];
        //ret+=c[i];
    }
    return ret;
}/*
void updata(int x,int val,int n)
{
   for(int i=x;i<=n;i+=lowbit(i))
    {
        c[i]+=val;
       // x+=lowbit((x));
    }
}*/
void updata(long long x,long long  val)
{
   // int i=l;
    for(int i=x;i<=n;i+=lowbit(i))
    {
       // c[i]+=val;
        arr[i]+=val;
    }
}
int main()
{
    ios::sync_with_stdio(false);

   // int n,m,k;
    cin>>n>>m;
    long long num;
    long long last=0,now;
    for(int i=1;i<=n;i++)
    {
       // cin>>arr[i];
        //updata(i,arr[i]);
        cin>>now;
        updata(i,now-last);
        last=now;
    }
    while(m--)
    {
        int l,r,val;
        int x;
        cin>>k;
        if(k==1)
        {
            cin>>l>>r>>val;
            updata(l,val);
            updata(r+1,-val);
        }
        else
        {
            cin>>x;
            //int ans=sum(r,c,n)-sum(l-1,c,n);
           // cout<<sum(r,c,n)<<" "<<sum(l,c,n)<<endl;
           cout<<sum(x,c)<<endl;
        }
    }
    return 0;
}

转载:https://www.luogu.org/problemnew/solution/P3368 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值