• hdu 1166 线段树 单点修改 + 询问区间求和 (线段树模板)


    题目来源:

    http://acm.hdu.edu.cn/showproblem.php?pid=1166

    借鉴大牛李的线段树模板

    const int Max_N=50100;
    int sum[Max_N<<2] ; // 线段树中每个点需要维护的区间和
    int x[Max_N]; // 输入数组
    //从下向上更新值
    void push_up(int root){
        sum[root] = sum[root<<1] + sum[root<<1|1]
    }
    // 建树,从根节点出发,根节点从1开始
    void make_tree(int L, int R, int root){
        if(L == R){
            sum[root] = x[L];
            return ;
        }
        int mid=(L + R)>>1;
        make_tree(L, mid, root<<1 );
        make_tree(mid+1, R, root<<1|1);
        push_up(root); // 先递归,后从下往上更新区间和值
    }
    // 将id值增加c, 调入的是整棵树的区间和根节点1
    void update(int id, int c, int L, int R, int root)
    {
        if(L == R){
            sum[root]+=c;
            return ;
        }
        int mid=(L + R)>>1;
        if(id<=mid )
            update(id, c, L, mid , root<<1);
        else
            update(id,c, mid+1, R, root<<1|1);
        push_up(root); // 更新是从上到下寻找需要更改的节点,然后从下往上地更新这些节点的区间和值
    }
    // 查询区间[l,r] 的 区间和值,在递归时不更改[l,r]区间的写法
    更一般(适应性越强)的写法

    int query(int l, int r, int L, int R, int root){
      if(l<=L && R <= r)
        return sum[root];
      int mid=(L + R)>>1;
      if(mid >= r)
        return query(l,r,L, mid, root<<1);
      else if(mid < l)
        return query(l,r,mid+1, R, root<<1|1);
      else
        return query(l,r,mid+1, R, root<<1|1)  +  query(l , r, L, mid, root<<1);
    }

    // 查询如果仅是加法, 就可以套这个模板
    int query(int l, int r, int L, int R, int root)
    {
        if(l <= L && R <= r)
            return sum[root];
        int mid=(L + R)>>1;
        int ans=0;
        if(l<= mid)
            ans+=query(l, r, L, mid, root<<1);
        if(r>mid)
            ans += query(l, r, mid+1, R, root<<1|1);
        return ans;
    }

    代码如下:

    #include <iostream>
    #include <algorithm>
    #include <stdlib.h>
    #include <stdio.h>
    #include <stack>
    #include <string>
    #include <string.h>
    #include<cstring>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <set>
    #include <math.h>
    #include <cmath>
    #include <map>
    #include <queue>
    using namespace std ;
    typedef long long LL ;
    
    // 线段树 单点修改,区间求和
    #define left(x) (x<<1)
    #define right(x) ((x<<1) + 1)
    const int maxn=50005;
    // 此线段树需要维护的附加信息是num,指的是每个节点所代表区间【l,r】之和
    struct tree{
        int l,r,num;
    };
    
    tree anode[maxn<<2]; // 线段树的节点估计为2*maxn 个
    int  data[maxn];
    // 附加信息的向上更新只与该节点或者节点的子节点有关,故可以扩展线段树
    void pushup(int n){
        anode[n].num=anode[left(n)].num + anode[right(n)].num;
        return ;
    }// 向上更新
    // 建线段树,从根节点1开始,调用为 build(1,n,1)
    void build(int l, int r, int n){
        int mid;
        mid=(l+r)>>1;
        if(l==r){
            anode[n].l=l;
            anode[n].r=r;
            anode[n].num=data[l];
            return ;
        }
        anode[n].l=l;
        anode[n].r=r;
        build(l, mid, left(n));
        build(mid+1, r, right(n));
        pushup(n);// 先递归,后从下往上更新区间和值
    }
    // 线段树更新,从根节点开始, 调用为 update(aim_id, new_num, 1)
    void update(int aim_id, int new_num, int n){
        if(anode[n].l == aim_id && anode[n].r== aim_id ){
            anode[n].num += new_num;
            return ;
        }
        if(anode[ left(n) ].l <= aim_id && anode[left(n)].r >=aim_id)
            update(aim_id, new_num, left(n));
        else update(aim_id, new_num, right(n));
        pushup(n);// 先递归需要更改的节点,然后从下往上的更新区间和值
        return ;
    }
    // 线段树查询,从根节点开始, 调用为 query(l,r, 1)
    int query(int l, int r, int n){
        if(anode[n].l ==l && anode[n].r ==r)
            return anode[n].num;
        int mid;
        mid= (anode[n].l + anode[n].r)>>1;
        if(mid >=r) return query(l,r,left(n));
        else if(mid< l) return query(l,r,right(n));
        else return query(l,mid,left(n)) + query(mid+1, r, right(n));
    }
    
    int  main(){
        int ca,k=1;
        scanf("%d",&ca);
        while(ca--){
                int n;
            scanf("%d",&n);
        for(int i=1 ; i<=n; i++)
            scanf("%d",&data[i]);
        build(1,n,1);
        printf("Case %d:
    ",k++);
        char od[12];
        while(1){
            scanf("%s",od);
            if(od[0] == 'E') break;
            int a,b;
            scanf("%d%d",&a,&b);
            if(od[0] == 'A')
                update(a,b,1);
            else if(od[0] == 'S')
                update(a,-b,1);
            else
                printf("%d
    ",query(a,b,1));
        }
        }
         return 0 ;
    }
  • 相关阅读:
    五种实用DOM方法总结
    九月工作总结
    八月下半月工作总结
    【工作总结】七月底-八月中
    权限管理功能的实现
    JavaWeb项目出现红色感叹号
    项目中遇到的AngularJs问题
    五月工作总结
    生成流水号的优化
    AngularJS scope 作用域的问题
  • 原文地址:https://www.cnblogs.com/zn505119020/p/3653592.html
Copyright © 2020-2023  润新知