树状数组模板

这里写图片描述
从图中可以看到,树状数组中用的C[ ],每个点都有一定的管辖范围;
如C[1]=a[1];
C[2]=a[1]+a[2];
C[3]=a[3];
C[4]=a[1]+a[2]+a[3]+a[4];等等;

基础模板:

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

这个函数主要是用来求的是某个点管辖范围;
如果是x+=x&(-x);就是得到的改点的父节点的值;比如x=4时;就能得到8;
而x-=x&(-x)的话,就是得到x这个点的管辖区间的下个区间的管辖点;
比如说,x=7,代入后6;不断循环到0能依次得到 6.。。4.;
把他们所有的管辖区间正好是1….7;

void add(int x, int num)
{
    while(x<=N)
    {
        c[x]+=num;
        x+=lowbit(x);
    }
}

这个函数,是用来修改树状数组的;
如果是一般的算法只用修改改点就可;但是树状数组必须修改所有改点被管辖的区间;

int getsum(int x)
{
    int s=0;
    while(x>0)
    {
        s+=c[x];
        x-=lowbit(x);
    }
    return s;
}

这个函数就是求区间和了。。比如getSum(7)的话,就是求a[1]+a[2]+…a[7];

进阶用法:
(1)区间更细+单点查询
思路:和一维数组求前缀和一样,右区间-左区间差值就是区间更新的值

int c[N];//树状数组//这里c[x]表示该店元素与左边元素的差值
int lowbit(int x)
{
    return x&(-x);
}
void add(int x, int num)
{
    while(x<=N)
    {
        c[x]+=num;
        x+=lowbit(x);
    }
}
void update(int x,int y,int num)
{
    add(x,num);
    add(y+1,-num);
}
int getsum(int x)
{
    int s=0;
    while(x>0)
    {
        s+=c[x];
        x-=lowbit(x);
    }
    return s;
}

(2)区间更新+区间查询
思路:sum(sum(C[j],j<=i)i<=x)
= x*C[1]+(x-1)*C[2]+……+C[x]
=(x+1)*sum(C[i],i<=x)-sum(i*C[i],i<=x);
这里用两个树状数组来维护区间更新的值
原始数组保存前缀和,则所求区间[x,y]的值为:ans[y]-ans[x-1]+query(x,y)

int c[2][N];//c[0][x]维护c[x]的值,c[1][x]维护c[x]*x的值
int ans[N];//原始数据数组的前缀和
int lowbit(int x)
{
    return x&(-x);
}
void add(int i,int x, int num)
{
    while(x<=N)
    {
        c[i][x]+=num;
        x+=lowbit(x);
    }
}
void update(int x,int y,int num)
{
    add(0,x,num);//更新c[0][x]的值(x[x])
    add(0,y+1,-num);
    add(1,x,x*num);//更新c[1][x]的值(c[x]*x)
    add(1,y+1,-(y+1)*num);
}
int sum(int i,int x)
{
    ll s=0;
    while(x>0)
    {
        s+=c[i][x];
        x-=lowbit(x);
    }
    return s;
}
int getsum(int x)
{
    return (x+1)*sum(0,x)-sum(1,x);
}
int query(int x,int y)
{
    return getsum(y)-getsum(x-1);
}

树状数组求区间最大值:

void Init()
{
    memset(a,0,sizeof(a));
    memset(h,0,sizeof(h));
}
int lowbit(int x)  
{  
    return x & (-x);  
}  
void updata(int x)  //更新操作为:a[i]=输入值,updata(i);(i从1开始)
{  
    int lx, i;  
    while (x <= n)  
    {  
        h[x] = a[x];  
        lx = lowbit(x);  
        for (i=1; i<lx; i<<=1)  
            h[x] = max(h[x], h[x-i]);  
        x += lowbit(x);  
    }         
}  
int query(int x, int y)  //区间[x,y]
{  
    int ans = 0;  
    while (y >= x)  
    {  
        ans = max(a[y], ans);  
        y --;  
        for (; y-lowbit(y) >= x; y -= lowbit(y))  
            ans = max(h[y], ans);  
    }  
    return ans;  
}  

下面还有一些树状数组的高级应用(由Lawrence_Jang大牛总结):
http://blog.csdn.net/lawrence_jang/article/details/8054173

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值