树状数组(这是一个好东西~~~)

我们还是用一道题来举例子吧
这里是题干:https://www.luogu.org/problemnew/show/P2068
首先,我们要引入一个神奇的东西:lowbit,我们用它来表示一个数的二进制的末尾有多少个0,我们可以用&运算来实现,
lowbit(x)=x&(-x);

之后我们用s[i]来表示从i开始到i-lowbit(i)+1个数的a的值,接着我们用sum[i]来表示前缀和,由于a数组是一个动态的数组,我们不能直接用a数组来加,我们先用改变的a数组来更新和他有关的s数组
所以sum[n]=s[n]加上一个数,由于sum[n]是表示a[1]+a[2]+…+a[n],s[n]=a[n]+a[n-1]+…a[n-lowbit(n)+1],所以还剩下a[1]到a[n-lowbit(n)],这又等于s[n-lowbit(n)]加上一个数,所以sum的状态转移方程为:
sum[n]=s[n]+sum[n-lowbit(n)];

下面我们来考虑一下改变a[x]对哪些s有影响:
首先x以前的s数组撑死用到x-1,所以都没有影响;
s[x]是一定要用到a[x]的,毋庸置疑~~
和sum数组的差不多,所有x+lowbit(x)可以到达的点都是 要用到a[x]的

最后附上代码:

#include<iostream>
using namespace std;
const int maxN=100100;
int n,w,a[maxN],s[maxN],sum[maxN];
int ans,num;

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

void preoperate()
{
    for(int i=1;i<=n;++i){
        for(int j=i;j>=i-lowbit(i)+1;--j)
            s[i]+=a[j];
    }
}

void change(int p,int value)
{
    while(p<=n){
        s[p]+=value;
        p+=lowbit(p);
    }
}

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

int main()
{
    //freopen("testdata.in","r",stdin);
    //freopen("shuzhuangshuzu.out","w",stdout);
    cin>>n>>w;
    for(int i=1;i<=w;++i){
        char ch;
        int p,q;
        cin>>ch>>p>>q;
        if(ch=='x'){
            change(p,q);
        }
        if(ch=='y'){
            cout<<findsum(q)-findsum(p-1)<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ljp946/article/details/81387667
今日推荐