zoukankan      html  css  js  c++  java
  • 树状数组的两种运用

    运用1

    单点修改,区间查询。

    add(pos,x)->在下标 pos 处加上 x
    query(pos)->返回 1 到 pos 的前缀和

    那么查询区间 [ l , r ]的操作就是query( r ) - query( l - 1 )

    例题——洛谷3374

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    const int maxn=500000+10;
    int a[maxn];
    int n,m;
    inline int lowbit(int x){
        return x&(-x);
    }
    inline void add(int pos,int val){
        while(pos<=n){
            a[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    inline int query(int pos){
        int res=0;
        while(pos>0){
            res+=a[pos];
            pos-=lowbit(pos);
        }
        return res;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            add(i,x);//赋初值 
        }
        for(int i=1;i<=m;i++){
            int op;
            scanf("%d",&op);
            if(op==1){
                int x,y;
                scanf("%d%d",&x,&y);
                add(x,y);
            }
            if(op==2){
                int x,y;
                scanf("%d%d",&x,&y);
                printf("%d
    ",query(y)-query(x-1));
            }
        }
        return 0;
    }
    

    运用二

    区间修改,单点查询

    add 和 query 的操作同运用一,但是使用方式不同:
    区间修改(给区间 [ l , r ]加上 d)->

    add(l,d);
    add(r+1,-d);

    单点查询(查询 pos 的值)->

    query(pos);

    例题——洛谷3368

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    const int maxn=500000+10;
    int c[maxn]; 
    int n;
    inline int lowbit(int x){
        return x&(-x);
    }
    inline void add(int pos,int val){
        while(pos<=n){
            c[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    inline int query(int pos){
        int res=0;
        while(pos>0){
            res+=c[pos];
            pos-=lowbit(pos);
        }
        return res;
    }
    int main(){
        int m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            add(i,x);
            add(i+1,-x);
        }
        for(int i=1;i<=m;i++){
            int op;
            scanf("%d",&op);
            if(op==1){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                add(x,z);
                add(y+1,-z);
            }
            if(op==2){
                int x;
                scanf("%d",&x);
                printf("%d
    ",query(x));
            }
        }
        return 0;
    }
    

    后记

    1. 两种运用的add 和 query 完全一样。
    2. 至于为什么,感觉不好解释,大概是差分的思想,现场手推一下即可。

    挖个坑

    据说还有一种区间修改区间查询的,过会儿再写。

  • 相关阅读:
    Spring Boot 配置加载顺序详解
    JVM总结篇
    nginx负载均衡的策略
    布隆过滤器的方式解决缓存穿透问题
    Spring Cloud Eureka自我保护机制(服务无法剔除)
    缓存穿透,缓存击穿,缓存雪崩解决方案分析
    高并发秒杀系统总结
    Linux环境进程间通信(一)
    HDU 1695 GCD(容斥定理)
    数据结构精要------冒泡与直接排序算法
  • 原文地址:https://www.cnblogs.com/yohanlong/p/6058147.html
Copyright © 2011-2022 走看看