树状数组维护前缀和

树状数组是用来维护序列前缀和的数据结构。它的修改与求和都是O(logn)的,效率非常高。

我们设序列为A,则树状数组c中,c[i]记录序列A的区间[ i-lowbit(i)+1 , i ]中所有数的和。 (树状数组是个好东西ovo) 

树状数组在进行区间操作时,要从上到下访问,进行单点操作时,要从下到上访问。 

树状数组维护序列前缀和的模版如下:

 

#include <iostream>
#include <cstdio>
#define maxn 500005
using namespace std;

int n,m;
int c[maxn];//c[i]存序列a中i-lowbit(i)+1到i的所有数的和(树状数组)

int read()
{
    int f=1,x=0;
    char ch;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return f*x;
}

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

void update(int x,int y)
{
    while(x<=n)
    {
        c[x]+=y;
        x+=lowbit(x);
    }
}//将序列a[x]加上y

int sum(int x)
{
    int res=0;
    while(x>0)
    {
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}//求序列1-x的和

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        //a[i]=read();
        int v=read();
        update(i,v);
    }
    for(int i=1;i<=m;i++)
    {
        int op,x,y;
        op=read();x=read();y=read();
        if(op==1)
        {
            update(x,y);
        }
        if(op==2)
        {
            int ans=sum(y)-sum(x-1);
            printf("%d\n",ans);
        }
    }

    return 0;
}

 

posted @ 2019-05-08 00:05  Black_Gzombie  阅读(803)  评论(0编辑  收藏  举报