ACM数据结构-树状数组

Posted TQCAI

tags:

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

模板:

int n;
int tree[LEN];

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

void update(int i,int d){//index,delta
    while(i<=n){
        tree[i]+=d;
        i+=lowbit(i);
    }
}

int getsum(int i){
    int ans=0;
    while(i>0){
        ans+=tree[i];
        i-=lowbit(i);
    }
    return ans;
}

示意图:

 


 

 

1.Ultra-QuickSort

大佬代码:

    //树状数组  
    #include<iostream>  
    #include<string.h>  
    #include<algorithm>  
    using namespace std;  
    #define MAX 500010  
    int c[MAX];  
    int aa[MAX];  
    int n;  
    typedef struct nano{  
        int val;  
        int order;  
    }node;  
    node in[MAX];  
    int lowbit(int x)  
    {  
        return x&(-x);  
    }  
    void update(int x,int val)  
    {  
        while(x<=n){  
            c[x]+=val;  
            x+=lowbit(x);  
        }  
    }  
    int sum(int x)  
    {  
        int s=0;  
        while(x>=1)  
        {  
            s+=c[x];  
            x-=lowbit(x);  
        }  
        return s;//一开始竟然忘记写了这个语句,还以为树状数组写错了呢  
    }  
    bool cmp(node a,node b){  
        return a.val<b.val;  
    }  
    int main(int argc, char *argv[])  
    {  
        //freopen("2299.in", "r", stdin);  
        while(scanf("%d",&n)==1&&n){  
            for(int i=1;i<=n;++i)  
            {  
                scanf("%d",&in[i].val);  
                in[i].order=i;  
            }  
            sort(in+1,in+n+1,cmp);  
            for(int i=1;i<=n;++i)  
                aa[in[i].order]=i;//离散化到小范围来  
            memset(c,0,sizeof(c));  
            long long ans=0;  
            for(int i=1;i<=n;++i)  
            {  
                update(aa[i], 1);  
                ans+=(i-sum(aa[i]));  
            }  
            printf("%lld\\n",ans);  
        }  
        return 0;  
    }  
View Code

大佬代码理解:

首先用结构体node:{val,order} 来存输入信息,用sort(in+1,in+n+1,cmp); 来根据val值进行排序,通过代码

        for(int i=1;i<=n;++i)  
            aa[in[i].order]=i;

构造数组aa,aa表示第i个数排第aa[i]位。(代码理解:i表示原本的索引,in[i].order表示排序后的索引)

逆序数计算:

        for(int i=1;i<=n;++i)  
        {  
            update(aa[i], 1);  
            ans+=(i-sum(aa[i]));  
        }  

 ans增量: 索引i之前比他大的数。

 


 

 

2.Mishka and Interesting sum

大佬代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
typedef  long long  ll;
typedef unsigned long long ull;
#define MM(a,b) memset(a,b,sizeof(a));
#define inf 0x7f7f7f7f
#define FOR(i,n) for(int i=1;i<=n;i++)
#define CT continue;
#define PF printf
#define SC scanf
const int mod=1000000007;
const int N=1e6+100;
int n,m,c[N],pre[N],sum[N],a[N],ans[N];
 
struct node{
   int l,r,pos;
}ne[N];
 
int lowbit(int i)
{
    return i&(-i);
}
 
void add(int p,int u)
{
    while(p<=n)
    {
        c[p]^=u;
        p+=lowbit(p);
    }
}
 
int query(int u)
{
   int res=0;
   while(u>=1)
   {
       res^=c[u];
       u-=lowbit(u);
   }
   return res;
}
 
bool cmp(node a,node b)
{
    return a.r<b.r;
}
 
map<int,int> mp;
int main()
{
    while(~scanf("%d",&n))
    {
        MM(sum,0);MM(pre,0);MM(c,0);
        mp.clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]^a[i];
            if(mp[a[i]]) pre[i]=mp[a[i]];
            mp[a[i]]=i;
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&ne[i].l,&ne[i].r);
            ne[i].pos=i;
        }
        sort(ne+1,ne+m+1,cmp);
        int i=1;
        for(int k=1;k<=m;k++)
        {
            for(;i<=ne[k].r;i++)
            {
                if(pre[i]) add(pre[i],a[i]);
                add(i,a[i]);
            }
            ans[ne[k].pos]=(query(ne[k].r)^query(ne[k].l-1)^sum[ne[k].r]^sum[ne[k].l-1]);
        }
        for(int i=1;i<=m;i++) printf("%d\\n",ans[i]);
    }
    return 0;
}
View Code

 


 3.模板编写训练1:P3368 【模板】树状数组 1

代码:

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>

#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 500010
#define MAX 1<<30
#define V vector<int>
#define ll long long  

using namespace std;

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

inline ll max(ll a,ll b){
    return a>b?a:b;
}

ll N;
ll tree[LEN];

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

ll getsum(int p){
    ll sum=0;
    while(p>0){
        sum+=tree[p];
        p-=lowbit(p);
    }
    return sum;
}

void update(int p,ll v){
    while(p<=N){
        tree[p]+=v;
        p+=lowbit(p);
    }
}

int main(){
//    freopen("D:\\\\CbWorkspace\\\\ACM数据结构\\\\树状数组\\\\模板1.txt","r",stdin);
    int m,i,t,op;
    int a,b;
    scanf("%d%d",&N,&m);
    for(i=1;i<=N;i++){
        I("%d",&t);
        update(i,t);
    }
    for(i=1;i<=m;i++){
        I("%d%d%d",&op,&a,&b); 
        switch(op){
            case 1:
                update(a,b);
                break;
            case 2:
                printf("%lld\\n",getsum(b)-getsum(a-1));
                break;
        }
    }
    return 0;
}
View Code

 


 

4.模板编写训练1:P3368 【模板】树状数组 2

代码:

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>

#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 500010
#define MAX 1<<30
#define V vector<int>
#define ll long long  

using namespace std;

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

inline ll max(ll a,ll b){
    return a>b?a:b;
}

ll N;
ll tree[LEN];

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

ll getsum(int p){
    ll sum=0;
    while(p>0){
        sum+=tree[p];
        p-=lowbit(p);
    }
    return sum;
}

void update(int p,ll v){
    while(p<=N){
        tree[p]+=v;
        p+=lowbit(p);
    }
}

int main(){
//    freopen("D:\\\\CbWorkspace\\\\ACM数据结构\\\\树状数组\\\\模板2.txt","r",stdin);
    int m,i,t,op,pre=0;
    int a,b,c;
    scanf("%d%d",&N,&m);
    for(i=1;i<=N;i++){
        I("%d",&t);
        update(i,t-pre);
        pre=t;
    }
    for(i=1;i<=m;i++){
        I("%d",&op); 
        switch(op){
            case 1:
                I("%d%d%d",&a,&b,&c); 
                update(a,c);
                update(b+1,-c);
                break;
            case 2:
                I("%d",&a); 
                printf("%lld\\n",getsum(a));
                break;
        }
    }
    return 0;
}
View Code

注:使用差分数组

 

以上是关于ACM数据结构-树状数组的主要内容,如果未能解决你的问题,请参考以下文章

ACM数据结构-树状数组

ACM算法目录

ACM入门之树状数组习题

ACM算法目录

HDU 1556 数据结构-树状数组-改段求点

ACM模板——线段树&树状数组