树状数组 1/30

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组 1/30相关的知识,希望对你有一定的参考价值。

树状数组分为三大类:
1.单点修改+区间求和
2.区间修改+单点求和(运用工具差分数组)
3.区间修改+区间求和(维护两个数组的前缀和)

典型的差分思想:
https://www.luogu.com.cn/problem/P3655

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=2e5+5;
ll N,S,Q,T,c[maxn],ls;
ll ans;
inline ll cc(ll x)

    if(x>0)
        return -S*x;
    return -T*x;

int main()

    scanf("%lld%lld%lld%lld",&N,&Q,&S,&T);
    for(register ll i=0;i<=N;i++)
    
        ll x;scanf("%lld",&x);
        c[i]=x-ls;
        ls=x;
        ans+=cc(c[i]);
    
    for(register ll i=1;i<=Q;i++)
    
        ll x,y,z;
        scanf("%lld%lld%lld",&x,&y,&z);
        ans-=cc(c[x]);
        c[x]+=z;
        ans+=cc(c[x]);
        if(y!=N)
        
            ans-=cc(c[y+1]);
            c[y+1]-=z;
            ans+=cc(c[y+1]);
        
        printf("%lld\\n",ans);
    
    return 0;


一.单点修改+区间求和
https://www.luogu.com.cn/problem/P3374

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=5e5+5;
ll c[maxn],d[maxn],n,m;

void add(ll i,ll val)

    while(i<=n)
    
        c[i]+=val;
        i+=i&(-i);
    

ll ask(ll i)

    ll ret=0;
    while(i>0)
    
        ret+=c[i];
        i-=i&(-i);
    
    return ret;

int main()

    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++)
    
        int h;
        scanf("%lld",&h);
        add(i,h);
    
    for(ll i=1;i<=m;i++)
    
        ll x,y,z;
        scanf("%lld%lld%lld",&x,&y,&z);
        if(x==1)
        
            add(y,z);
        
        else
        
            cout<<ask(z)-ask(y-1)<<endl;
        
    
    return 0;

二.区间修改+单点求和(运用工具差分数组)
https://www.luogu.com.cn/problem/P3368

#include <bits/stdc++.h>

using namespace std;
const int maxn=5e5+5;
int n,m,a[maxn],c[maxn],d[maxn];
void add(int p,int x)

    while(p<=n)
    
        c[p]+=x,p+=p&-p;
    

void range_add(int l,int r,int x)

    add(l,x),add(r+1,-x);

int ask(int p)

    int res=0;
    while(p>0)
        res+=c[p],p-=p&-p;
    return res;

int main()

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    
        scanf("%d",&a[i]);
        add(i,a[i]-a[i-1]);
    
    for(int i=1;i<=m;i++)
    
        int x,y,z,p;scanf("%d",&x);
        if(x==1)
        
            scanf("%d%d%d",&y,&z,&p);
            range_add(y,z,p);
        
        else if(x==2)
        
            scanf("%d",&y);
            printf("%d\\n",ask(y));
        
    
    return 0;

以上是关于树状数组 1/30的主要内容,如果未能解决你的问题,请参考以下文章

树状数组和线段树有啥区别?

树状数组的树状数组的经典操作

树状数组模板

数据结构之树状数组从零认识树状数组

树状数组 / 二维树状数组

浅谈树状数组