树状数组

个人觉得树状数组十分好用,虽然功能十分简单,但却可以用来优化其他题中的查询与修改...

比较好的博客

数据结构就没学多少,就学好这个吧!

单点修改与区间查询:

#include<bits/stdc++.h>
using namespace std;
const int N=501000;
int n,m,a[N],c[N];
inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}
inline int lowbit(int x) {return x&(-x);}
inline void add(int x,int k)
{
    for(;x<=n;x+=lowbit(x)) c[x]+=k; 
}
inline int ask(int x)
{
    int ans=0;
    for(;x>0;x-=lowbit(x)) ans+=c[x];
    return ans;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(register int i=1;i<=n;++i) a[i]=read(),add(i,a[i]);
    for(register int i=1;i<=m;++i)
    {
        int p=read(),x=read(),y=read();
        if(p==1) add(x,y);
        else if(p==2) printf("%d
",ask(y)-ask(x-1));
    }
    return 0;
}

区间修改与单点查询:

#include<bits/stdc++.h>
using namespace std;
const int N=501000;
int n,m,a[N],c[N];
inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int k)
{
    for(;x<=n;x+=lowbit(x)) c[x]+=k;
}
inline int ask(int x)
{
    int ans=0;
    for(;x>0;x-=lowbit(x)) ans+=c[x];
    return ans;
}
int main()
{
//    freopen("1.in","r",stdin);
    n=read();m=read();
    for(register int i=1;i<=n;++i) a[i]=read(),add(i,a[i]-a[i-1]);
    for(register int i=1;i<=m;++i)
    {
        int p=read();
        if(p==1) 
        {
            int x=read(),y=read(),k=read();
            add(x,k);add(y+1,-k);
        }
        else if(p==2)
        {
            int x=read();
            printf("%d
",ask(x));
        }
    }
    return 0;
}

 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=101000;
ll n,m,sum1[N],sum2[N],a[N];
inline ll read()
{
    ll x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}
inline ll lowbit(ll x){return x&(-x);}
inline void add(ll x,ll k)
{
    int i=x;
    for(;x<=n;x+=lowbit(x)) sum1[x]+=k,sum2[x]+=(i-1)*k;
}
inline ll ask(ll x)
{
    ll ans=0,i=x;
    for(;x>0;x-=lowbit(x)) ans+=i*sum1[x]-sum2[x];
    return ans;
}
int main()
{
    freopen("1.in","r",stdin);
    n=read();m=read();
    for(register int i=1;i<=n;++i) a[i]=read(),add(i,a[i]-a[i-1]);
    for(register int i=1;i<=m;++i)
    {
        int p=read();
        if(p==1) 
        {
            ll x=read(),y=read(),k=read();
            add(x,k);add(y+1,-k);
        }
        else if(p==2) 
        {
            ll x=read(),y=read();
            printf("%ld
",ask(y)-ask(x-1));
        }
    }
    return 0;
}

好,这样就全齐了,总结一下,其中单点修改,单点查询,区间查询就是比较传统的树状数组..而区间修改则需要更改为差分,区间查询则更需要多开一个数组...

例题:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,k,c[1001000],s,ans=1;
inline ll read()
{
    ll x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} 
    return x*ff;
}
inline ll lowbit(ll x) {return x&(-x);}
inline void add(ll x,ll k)
{
    for(;x<=n;x+=lowbit(x)) c[x]+=k;
}
inline ll ask(ll x)
{
    ll ans=0;
    for(;x>0;x-=lowbit(x)) ans+=c[x];
    return ans;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();k=read();s=1;
    for(register ll i=1;i<=n;++i)
    {
        ll x=(k*i+1)%n;
        if(!x) x=n;
        if(x<s)
        {
            if((s-x)<(n-s+x)) ans+=ask(s-1)-ask(x);
            else ans+=2*(i-1)-ask(s)+ask(x-1);
        }
        else if(x>s)
        {
            if((x-s)<(n-x+s)) ans+=ask(x-1)-ask(s);
            else ans+=2*(i-1)-ask(x)+ask(s-1);
        } 
        add(x,1);add(s,1);s=x;ans++;
        printf("%ld ",ans);
    }
    return 0;
}

 二维:

单点修改与区间查询.

这里注意0的lowbit就行...

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1100;
ll c[N][N],n,m,a[N][N];
inline ll read()
{
    ll x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}
inline ll lowbit(ll x) {return x&(-x);}
inline void add(ll x,ll y,ll k)
{
    ll yy=y;
    for(;x<=n;x+=lowbit(x)) 
        for(y=yy;y<=n;y+=lowbit(y)) c[x][y]+=k;
}
inline ll ask(ll x,ll y)
{
    ll yy=y,ans=0;
    for(;x>0;x-=lowbit(x))
        for(y=yy;y>0;y-=lowbit(y)) ans+=c[x][y];
    return ans;    
}
int main()
{
    freopen("1.in","r",stdin);
    n=read()+1;
    for(;;)
    {
        int p=read();
        if(p==3) break;
        else if(p==1) 
        {
            ll x=read()+1,y=read()+1,k=read();
            add(x,y,k);
        }        
        else if(p==2)
        {
            ll x1=read()+1,y1=read()+1,x2=read()+1,y2=read()+1;
            printf("%lld
",ask(x2,y2)-ask(x1-1,y2)-ask(x2,y1-1)+ask(x1-1,y1-1));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/gcfer/p/11609887.html