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

    题面

    已知一个数列,你需要进行下面两种操作:
    1.将某一个数加上x
    2.求出某区间每一个数的和

    题解1

    单点修改+区间查询。
    关于树状数组的理解,补上一点。位运算的操作其实对应的就是任意一个整数在二进制下都可以被拆分为2^i+2^i-1+…这种形式,所以将1~n的区间也拆成这种好几个长为2^i的和并加起来。所以树状数组维护的是前缀和,区间查询是用的前缀和的性质也。

    #include<iostream>
    using namespace std;
    const int maxn = 500010;
    
    int n, m, a[maxn];
    void add(int x, int v){
        for(int i = x; i <= n; i += i&-i){
            a[i] += v;
        }
    }
    int query(int x){
        int ans = 0;
        for(int i = x; i >= 1; i -= i&-i){
            ans += a[i];
        }
        return ans;
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>m;
        for(int i = 1; i <= n; i++){
            int x;  cin>>x;  add(i,x);
        }
        for(int i = 1; i <= m; i++){
            int op, x, y;
            cin>>op>>x>>y;
            if(op == 1){
                add(x,y);
            }else{
                cout<<query(y)-query(x-1)<<"
    ";
            }
        }
        return 0;
    }

    题解2

    线段树当然也是可以做的啦。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn = 500010;
    
    int a[maxn];
    struct node{
        int l, r;
        int val;
    }sgt[maxn<<2];
    void build(int p, int l, int r){
        sgt[p].l = l, sgt[p].r = r;
        if(l == r){
            sgt[p].val = a[l];
        }else{
            int m = (l+r)/2;
            build(p*2,l,m);
            build(p*2+1,m+1,r);
            sgt[p].val = sgt[p*2].val+sgt[p*2+1].val;
        }
    }
    void change(int p, int x, int v){
        if(sgt[p].l == sgt[p].r){
            sgt[p].val += v;
            return ;
        }
        int m = (sgt[p].l+sgt[p].r)/2;
        if(x <= m)change(p*2,x,v);
        if(x > m)change(p*2+1,x,v);
        sgt[p].val = sgt[p*2].val+sgt[p*2+1].val;
    }
    int query(int p, int l, int r){
        if(l <= sgt[p].l && sgt[p].r <= r)return sgt[p].val;
        int m = (sgt[p].l+sgt[p].r)/2, ans = 0;
        if(l <= m)ans += query(p*2,l,r);
        if(r > m)ans += query(p*2+1,l,r);
        return ans;
    }
    
    int main(){
        ios::sync_with_stdio(false);
        int n, m;
        cin>>n>>m;
        for(int i = 1; i <= n; i++)cin>>a[i];
        build(1,1,n);
        for(int i = 1; i <= m; i++){
            char ch;  cin>>ch;
            if(ch == '2'){
                int x, y;  cin>>x>>y;
                cout<<query(1,x,y)<<"
    ";
            }else{
                int x, y;  cin>>x>>y;
                change(1,x,y);
            }
        }
        return 0;
    }

    题解3

    啊,是否疲倦了现在的线段树
    太弱,还递归!

    那我们就欢乐的学习另外一种神奇的线段树吧!(雾
    他叫做zkw线段树

    首先我们来看一个ppt,《统计的力量》这个是发明人的PPT(啊,ppt内的代码是错的……
    統計的力量

    #include<cstdio>
    const int maxn = 500050;
    
    int p, sgt[maxn<<2];
    void build(int n){
        for(p = 1; p <= n+1; p<<=1);
        for(int i = 1; i <= n; i++)
            scanf("%d", &sgt[p+i]);
        for(int i = p-1; i >= 1; i--)
            sgt[i] = sgt[i<<1]+sgt[i<<1|1];
    }
    void update(int x, int v){
        sgt[x+=p] += v;
        for(x>>=1; x >= 1; x>>=1)
            sgt[x] = sgt[x<<1]+sgt[x<<1|1];
    }
    long long query(int l, int r){
        l = l+p-1, r = r+p+1;
        long long ans = 0;
        for(; l^r^1; l>>=1,r>>=1){
            if(~l&1)ans += sgt[l^1];
            if(r&1)ans += sgt[r^1];
        }
        return ans;
    }
    
    int main(){
        int n, m;
        scanf("%d%d
    ", &n,&m);
        build(n);
        for(int i = 1; i <= m; i++){
            int op, x, y;  scanf("%d%d%d", &op,&x,&y);
            if(op == 1)update(x,y);
            else printf("%lld
    ", query(x,y));
        }
        return 0;
    }
  • 相关阅读:
    logistics regression
    dir 以及 attrib
    python 爬取有道翻译
    spss 逐步回归
    JQuery传值给.ashx乱码
    字符串转换成json的三种方式
    启动数据库SQL Server Service Broker
    ASP.NET两种缓存方式
    VS安装控件后报错
    sql server中有不是全数字的字符串
  • 原文地址:https://www.cnblogs.com/gwj1314/p/9444886.html
Copyright © 2011-2022 走看看