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

    模板:

    const int maxn=10000;
    
    //注意:0 是无效下标
    int n;//1-n
    
    //c[i]所掌控的前缀信息的下标范围是[i−lowbit(i)+1,i],树状数组 c 维护 ai 的前缀和
    int c[maxn+1];
    
    //lowbit(x):x的二进制表示里最低位的1与更低位的所有0所组成的二进制数的十进制结果
    inline int lowbit(int x){ return x & -x; }
    
    //ax+=v
    void add(int x,int v) {
        for (int i=x;i<=n;i+=lowbit(i))
            c[i]+=v;
    }
    
    //求和a1+a2+...+ax
    int sum(int x){
        int s=0;
        for(int i=x;i>0;i-=lowbit(i))
            s+=c[i];
        return s;
    }
    
    //求和al+a(l+1)+...+ar
    int sum(int l,int r) { return sum(r)-sum(l-1); }

    洛谷3374(模板1) 单点修改+区间查询

    #include <cstdio>
    using namespace std;
    const int maxn=5e5;
    
    int n;
    int c[maxn+3];
    
    inline int lowbit(int x){ return x & -x; }
    
    
    //单点修改
    void add(int x,int v) {
        for (int i=x;i<=n;i+=lowbit(i))
            c[i]+=v;
    }
    
    //区间查询
    int sum(int x){
        int s=0;
        for(int i=x;i>0;i-=lowbit(i))
            s+=c[i];
        return s;
    }
    
    int sum(int l,int r) { return sum(r)-sum(l-1); }
    
    int main(){
        int m,x,a,b;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;++i){
            scanf("%d",&x);
            add(i+1,x);
        }
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&x,&a,&b);
            if(x==1){
                add(a,b);
            }else {
                printf("%d
    ",sum(a,b));
            }
        }
        return 0;
    }

    开始cin cout,TLE,改成scanf后AC。

    洛谷3368(模板2)单点查询+区间修改

    #include <cstdio>
    using namespace std;
    const int maxn=5e5;
    
    int n;
    int c[maxn+3];
    
    inline int lowbit(int x){ return x & -x; }
    
    void add(int x,int v) {
        for (int i=x;i<=n;i+=lowbit(i))
            c[i]+=v;
    }
    
    int sum(int x){
        int s=0;
        for(int i=x;i>0;i-=lowbit(i))
            s+=c[i];
        return s;
    }
    
    void add(int l,int r,int v){ add(l,v); add(r+1,-v); }
    
    int main(){
        int m,x,a,b,k;
        scanf("%d%d",&n,&m);
        int last=0,now;
        for(int i=0;i<n;++i){ //c里不是差分数组,而是差分数组以树状数组的方式存
            scanf("%d",&now);
            add(i+1,now-last);
            last=now;
        }
        for(int i=0;i<m;++i){
            scanf("%d",&x);
            if(x==1){       //[l,r]区间修改变为在差分数组两端打标记
                scanf("%d%d%d",&a,&b,&k);
                add(a,b,k);
            }else {         //单点查询变为对差分数组求前缀和
                scanf("%d",&a);
                printf("%d
    ",sum(a));
            }
        }
        return 0;
    }

    洛谷3372(模板3)区间修改+区间查询

     
    #include <cstdio>
    using namespace std;
    const int maxn=1e5;
    typedef long long ll;
    ll n;
    ll c1[maxn+3],c2[maxn+3];//用树状数组c1维护delti前缀和,用树状数组c2维护i⋅delti前缀和
    
    inline ll lowbit(ll x){ return x & -x; }
    
    void add(ll *c,ll x,ll v) {
        for (int i=x;i<=n;i+=lowbit(i))
            c[i]+=v;
    }
    
    ll sum(ll *c,ll x){
        ll s=0;
        for(int i=x;i>0;i-=lowbit(i))
            s+=c[i];
        return s;
    }
    
    int main(){
        ll m,x,a,b,k;
        scanf("%lld%lld",&n,&m);
        ll last=0,now;
        for(int i=0;i<n;++i){
            scanf("%lld",&now);
            add(c1,i+1,now-last);
            add(c2,i+1,(i+1)*(now-last));
            last=now;
        }
        for(int i=0;i<m;++i){
            scanf("%lld",&x);
            if(x==1){
                scanf("%lld%lld%lld",&a,&b,&k);
                add(c1,a,k),add(c1,b+1,-k);
                add(c2,a,k*a),add(c2,b+1,-k*(b+1));//delt数组两端加k,i*delt数组两端就要加i*k
            }else {
                scanf("%lld%lld",&a,&b);
                printf("%lld
    ",((b+1)*sum(c1,b)-sum(c2,b))-(a*sum(c1,a-1)-sum(c2,a-1)));
            }
        }
        return 0;
    }

    洛谷1908 逆序对(归并排序or树状数组)下面是树状数组code

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn=5e5;
    typedef long long ll;
    int n;
    int a[maxn+3],b[maxn+3];
    ll c1[maxn+3];
    
    inline ll lowbit(ll x){ return x & -x; }
    
    void add(ll *c,ll x,ll v) {
        for (int i=x;i<=n;i+=lowbit(i))
            c[i]+=v;
    }
    
    ll sum(ll *c,ll x){
        ll s=0;
        for(int i=x;i>0;i-=lowbit(i))
            s+=c[i];
        return s;
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+1+n);
        for(int i=1;i<=n;++i){//离散化
            a[i]=lower_bound(b+1,b+1+n,a[i])-b;
        }
        ll ans=0;
        for(int i=1;i<=n;++i){//边加入边计算,每次加入a[i]对总逆序对的贡献(只向前看)
            add(c1,a[i],1);
            ans+=i-sum(c1,a[i]);//排在a[i]前面,并且大于a[i]的个数
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Use MusicBrainz in iOS(三)查询专辑的完整信息
    内存寻址一(分段)
    POJ 1018 Communication System (动态规划)
    利用Eclipse中的Maven构建Web项目(二)
    cocos2d-x2.2.3学习
    (排序算法整理)NEFU 30/32
    POJ 1066 昂贵的聘礼
    2014年腾讯暑假实习软件开发笔试题汇总
    Android学习之——自己搭建Http框架(1)
    C 语言之预处理 ---------文件包括
  • 原文地址:https://www.cnblogs.com/Maxx-el/p/13402259.html
Copyright © 2011-2022 走看看