zoukankan      html  css  js  c++  java
  • 关于树状数组

                   关于树状数组

    线段树和树状数组在noip中本人觉得挺重要的,而且比较难写。

    我们先来看树状数组。

    look at 这个图

    那么我们会发现一个有趣的性质。

    设节点编号为n,那么这个节点管辖的区间为2k(其中k为n二进制末尾0的个数)个元素。

    这个区间最后一个元素必然为An。

    所以:Cn=A(n-2k+1)+...An

    神奇吧。

    通常,我们管2k叫做lowbit(n),哇这个名字真魔性。

    计算方法呢就是n&(-n) 

    原理呢就是计算机中的补码存储方式。->挺好的

    关于查询:

    这个时候我们要用到前缀和,通过查询前缀和来实现查询区间和。

    那么我们如何实现呢,前缀和相减即可。

    关于修改:

    代码:(add与query)

    众所周知(在我看来),树状数组不论是空间还是时间,都是完胜线段树的,那么我们就来分析一下它的复杂度:

    1.查询的时候,因为每次都会让二进制表示中的最后一个1变为0,所以是O(log2n)。

    2.修改的时候,同样也是每次让二进制表示中的最后一个1变为0,所以是O(log2n)。

    相比于其他大型数据结构如线段树啊,splay啊,他在常数上非常有优势。

    不过缺点是,他的应用面比较窄,基本是只能维护数字之后这一种信息。你可以在各大网站的模板题中看出来。

    代码实现:

    【模板】树状数组 1

    #include<cstdio>
    #include<iostream>
    int n,m,a[500010];
    void add(int l,int r) {
        while(l<=n) a[l]+=r,l+=l&(-l);
    }
    int sum(int x) {
        int num=0;
        while(x) num+=a[x],x-=x&(-x);
        return num;
    }
    int main() {
        scanf("%d%d",&n,&m);
        for(int x,i=1;i<=n;i++) 
            scanf("%d",&x),add(i,x);
        for(int i=1,a,b,c;i<=m;i++){
            scanf("%d%d%d", &a, &b, &c);
            if(a==1) add(b,c);
            else printf("%d
    ",sum(c)-sum(b-1));
        }
        return 0;
    }

    【模板】树状数组 2

    #include <iostream>
    #include <cstdio>
    #define lowbit(x) x & -x
    using namespace std;
    long long tree[500005];
    int n, m;
    void add(int x, long long num) {
        while (x <= n) {
            tree[x] += num;
            x += lowbit(x);
        }
    }
    long long query(int x) {
        long long ans = 0;
        while (x) {
            ans += tree[x];
            x -= lowbit(x);
        }
        return ans;
    }
    int main() {
        freopen("in.txt", "r", stdin);
        scanf("%d%d", &n, &m);
        long long last = 0, now;
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &now);
            add(i, now - last);
            last = now;
        }
        int flg;
        while (m--) {
            scanf("%d", &flg);
            if (flg == 1) {
                int x, y;
                long long k;
                scanf("%d%d%lld", &x, &y, &k);
                add(x, k);
                add(y + 1, -k);
            } else if (flg == 2) {
                int x;
                scanf("%d", &x);
                printf("%lld
    ", query(x));
            }
        }
        return 0;
    }

    上面我们讨论了一维的,下面我们来讨论一下二维的。

    其实很简单,就是树状数组套树状数组。

    代码:

    具体实现:

    Mobile phones

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 1100
    int n,c[N][N];
    inline int lowbit(int x){
        return x&-x;
    }
    void updata(int x,int y,int v){
        for(int i=x;i<=n;i+=lowbit(i)){
            for(int j=y;j<=n;j+=lowbit(j)){
                c[i][j]+=v;
            }
        }
    }
    int sum(int x,int y){
        int res=0;
        for(int i=x;i;i-=lowbit(i)){
            for(int j=y;j;j-=lowbit(j)){
                res+=c[i][j];
            }
        }
        return res;
    }
    int getsum(int x1,int y1,int x2,int y2){
         return sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1);
    }
    int main(){
        int opt,l,r,x,y,a,b,t;
        while(scanf("%d",&opt)!=EOF){
            if(opt==0){
                scanf("%d",&n);
                memset(c,0,sizeof(c));
            }
            else if(opt==1){
                scanf("%d%d%d",&x,&y,&a);
                updata(x+1,y+1,a);
            }
            else if(opt==2){
                scanf("%d%d%d%d",&l,&b,&r,&t);
                printf("%d
    ",getsum(l+1,b+1,r+1,t+1));
            }
        }
        return 0;
    }

    总结:树状数组作为一种方便、高效的数据结构,通常和其它的一些算法一起使用,而将树状数组作为主算法的题目反而较少。熟练掌握树状数组,是每个选手想要成功应该做到的。

    下一篇我们要讲树状数组的升级版,线段树,拥有比树状数组更强大的功能,而且比较好理解,只不过更繁琐一些,在复杂度方面不如树状数组。

    何事悲凉,你为秋。

  • 相关阅读:
    http 400 错误的请求怎么解决
    HTTP 404
    怎样在WIN7系统下安装IIS
    未能找到类型或命名空间名称“XXXX”(是否缺少 using 指令或程序集引用?) 转
    错误 1 未能找到元数据文件“C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NET Files/wwwroot/7cb4fcd
    mklink命令转移win7系统盘文件夹users和programdata(附xp的方法)
    前端进阶之路:初涉Less
    原生js实现tooltip提示框的效果
    jquery+css实现邮箱自动补全
    前端面试中常见的算法问题读后整理
  • 原文地址:https://www.cnblogs.com/GTBD/p/9295725.html
Copyright © 2011-2022 走看看