重学树状数组

拍个广告  校内大佬  

问题背景

对于包含n个元素的整数数组a,每次可以
1. C(i, j): 修改一个元素a[i] = j                        //单点修改                    
2. Q(i): 询问前缀Si=a1+a2+…+ai的值        //  区间查询

lowbit值

在说树状数组之前,我们不得不说一下lowbit值

  1. 公式  :  lowbit(x)=x and -x
  2. 含义 :   令LOWBIT(i)=2^k    其中k为i在二进制下末尾0的个数 

例如 :     6--->110   k=1  lowbit(6)= 2^1=2

树状数组是一个动态维护前缀和的数据结构

单点修改————沿红线向后

求前缀和————沿绿线向前

P3374 【模板】树状数组 1  https://www.luogu.org/problemnew/show/P3374

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int n,m;
int a[500050]={0},c[500050]={0};

int lowbit(int x)
{
    return x&(-x);
}
void add(int i,int x)
{
    for(i;i<=n;i+=lowbit(i))     c[i]+=x;
}

int getsum(int i)
{
    int re=0;
    for(i;i>0;i-=lowbit(i))      re+=c[i];
    return re;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)  scanf("%d",&a[i]),add(i,a[i]);
    for(int i=1;i<=m;i++)
    {
        int c,x,y;
        scanf("%d%d%d",&c,&x,&y);
        if(c==1)  add(x,y);
        else printf("%d\n",getsum(y)-getsum(x-1));
    }
    
    return 0;
}

P3368 【模板】树状数组 2   https://www.luogu.org/problemnew/show/P3368

  

来介绍一下差分

设数组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;

所以  ,树状数组 本质上只能 单点修改,求前缀和

但与差分结合后  可以在结果上等价于 区间修改 ,查找单点  

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int n,m;
int a[500050]={0},c[500050]={0};

int lowbit(int x)
{
    return x&(-x);
}

void add(int i,int x)
{
    for(i;i<=n;i+=lowbit(i))  c[i]+=x;
}

int getsum(int i)
{
    int re=0;
    for(i;i>0;i-=lowbit(i))   re+=c[i];
    return re;
}


int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
    for(int i=n;i>=1;i--)  a[i]-=a[i-1],add(i,a[i]);
    for(int i=1;i<=m;i++)
    {
        int c;
        scanf("%d",&c);
        if(c==1)  
        {
            int x,y,k;
            scanf("%d%d%d",&x,&y,&k);
            add(x,k);
            add(y+1,-k);
        }
        else 
        {
            int x;
            scanf("%d",&x);
            printf("%d\n",getsum(x));
        }
    }
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42146446/article/details/81134246