zoukankan      html  css  js  c++  java
  • 树状数组模板1

    题目链接:https://www.luogu.org/problemnew/show/P3374

      树状数组和线段树一样,也是一个结点表示一个段,只不过线段树是采用二分思想来表示一个线段,而树状数组不是。对于原数据a[],树状数组tr[],tr[n]=tr[n-2^k+1]+...+tr[n],其中k是n在二进制下末尾0的个数,2^k可通过x&(-x)来获得。树状数组的适用性约束较大,一般用于对点更新(O(logn)),对区间查询(O(logn)),而不建议用来对区间更新(O(nlogn)),还不如在原数组上操作(O(n)),不建议对点查询。而且必须满足减法规则才能使用树状数组,即比如求和就满足sum(a,b)=sum(1,b)-sum(1,a-1),而求最大值就不满足减法规则。

      在很多情况下线段树都可以用树状数组实现,凡是能用树状数组实现的都可以用线段树实现。树状数组相比线段树来说更节省空间且复杂读更低,但局限性稍大。

      树状数组和线段树都在题目要求进行频繁的修改和查询操作时使用。线段树的使用更灵活,主要是考虑每个结点需要记录什么,这个记录的值在修改过程需要怎么维护。线段树之所以存在的理由是因为它能适用于很多方面,不仅仅是区间、单点的查询修改,还有标记等等,可以用于模拟、DP等等,而且空间经过离散化以后也可以相对压缩,所以适用范围线段树更加广一些。

    AC代码:

    #include<cstdio>
    #include<cctype>
    using namespace std;
    
    inline int read(){
        int x=0,f=0;char c=0;
        while(!isdigit(c)){f|=c=='-';c=getchar();}
        while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
        return f?-x:x;
    }
    
    int n,m,tr[500005];
    
    int lowbit(int x){
        return x&(-x);
    }
    
    void update(int pos,int num){
        while(pos<=n){
            tr[pos]+=num;
            pos+=lowbit(pos);
        }
    }
    
    int query(int pos){
        int ans=0;
        while(pos>0){
            ans+=tr[pos];
            pos-=lowbit(pos);
        }
        return ans;
    }
    
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;++i){
            int tmp=read();
            update(i,tmp);
        }
        while(m--){
            int op=read(),x=read(),y=read();
            if(op==1)
                update(x,y);
            else
                printf("%d
    ",query(y)-query(x-1));
        }
        return 0;
    }
  • 相关阅读:
    DBHelper
    jsTree使用
    爬虫系列之Scrapy框架
    Mongodb安装
    爬虫系列之mongodb
    爬虫学习目录
    爬虫之selenium模块
    爬虫简介与requests模块
    爬虫数据解析的三方式
    线程相关
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10796975.html
Copyright © 2011-2022 走看看