zoukankan      html  css  js  c++  java
  • 线段树模板

    线段树模板

    HDU - 1166 - 敌兵布阵

    本题为单点修改+区间查询 求和

    #include <cstdio>
    // #include <cstdlib>
    using namespace std;
    #define N (50000+5)
    int arr[N];
    int tree[N<<2];
    void push_up(int root){ // 向上传播
        tree[root] = tree[root<<1] + tree[root<<1|1];
    }
    void build_tree(int left,int right,int root){
        if(left == right){
            tree[root] = arr[left];
        }else{
            int mid = (left+right)>>1;
            build_tree(left,mid,root<<1);
            build_tree(mid+1,right,root<<1|1);
            push_up(root);
        }
    }
    
    void update(int left,int right,int root,int pos,int delta){ // 单点修改
        if(left == right){
            tree[root] += delta;
        }else{
            int mid = (left+right)>>1;
            if(pos <= mid){
                update(left,mid,root<<1,pos,delta);
            }else{
                update(mid+1,right,root<<1|1,pos,delta);
            }
            push_up(root);
        }
    }
    
    int query(int left,int right,int root,int ask_left,int ask_right){
        if(ask_right < left || ask_left > right){ // 待查询区间与当前区间交集为空
            return 0;
        }
        if(left >= ask_left && ask_right >= right){ // 待查询区间包含当前区间
            return tree[root];
        }
        int mid = (left+right)>>1;
        return query(left,mid,root<<1,ask_left,ask_right) + query(mid+1,right,root<<1|1,ask_left,ask_right);
    }
    int main(){
        int T;
        scanf("%d",&T);
        for(int g = 1; g <= T; g++){
            printf("Case %d:
    ",g);
            int n;
            scanf("%d",&n);
            for(int i = 1; i <= n; i++){
                scanf("%d",&arr[i]);
            }
            build_tree(1,n,1);
            char cmd[10];
            int i,j;
            while(1){
                scanf("%s",cmd);
                if(cmd[0] == 'Q'){
                    scanf("%d%d",&i,&j);
                    printf("%d
    ",query(1,n,1,i,j));
                }else if(cmd[0] == 'A'){
                    scanf("%d%d",&i,&j);
                    update(1,n,1,i,j);
                }else if(cmd[0] == 'S'){
                    scanf("%d%d",&i,&j);
                    update(1,n,1,i,-j);
                }else{
                    break;
                }
            }
        }
        // system("pause");
        return 0;
    }
    

    HDU - 1754 -I Hate It

    本题为单点修改+区间查询 最值

    #include <cstdio>
    #include <cstdlib>
    using namespace std;
    #define N (200000+5)
    #define MAX(a,b) (a>b?a:b)
    int arr[N];
    int tree[N<<2];
    void push_up(int root){ // 向上传播
        int a = tree[root<<1];
        int b = tree[root<<1|1];
        tree[root] = MAX(a,b); 
    }
    void build_tree(int left,int right,int root){
        if(left == right){
            tree[root] = arr[left];
        }else{
            int mid = (left+right)>>1;
            build_tree(left,mid,root<<1);
            build_tree(mid+1,right,root<<1|1);
            push_up(root);
        }
    }
    
    void update(int left,int right,int root,int pos,int delta){ // 单点修改
        if(left == right){
            tree[root] = delta;
        }else{
            int mid = (left+right)>>1;
            if(pos <= mid){
                update(left,mid,root<<1,pos,delta);
            }else{
                update(mid+1,right,root<<1|1,pos,delta);
            }
            push_up(root);
        }
    }
    
    int query(int left,int right,int root,int ask_left,int ask_right){
        if(ask_right < left || ask_left > right){ // 待查询区间与当前区间交集为空
            return 0;
        }
        if(left >= ask_left && ask_right >= right){ // 待查询区间包含当前区间
            return tree[root];
        }
        int mid = (left+right)>>1;
        int ll = query(left,mid,root<<1,ask_left,ask_right);
        int rr = query(mid+1,right,root<<1|1,ask_left,ask_right);
        return MAX(ll,rr);
    }
    int main(){
        int n,q;
        while(scanf("%d%d",&n,&q)!=EOF){
            for(int i = 1; i <= n; i++){
                scanf("%d",&arr[i]);
            }
            build_tree(1,n,1);
            char cmd[10];
            int i,j;
            while(q--){
                scanf("%s",cmd);
                if(cmd[0] == 'Q'){
                    scanf("%d%d",&i,&j);
                    printf("%d
    ",query(1,n,1,i,j));
                }else{
                    scanf("%d%d",&i,&j);
                    update(1,n,1,i,j);
                }
            }
        }
        // system("pause");
        return 0;
    }
    

    POJ - 3468 - A Simple Problem With Integers

    注意一点:

    只要某个结点的祖先结点没有lazy标记,那么这个结点的值就是正确的

    当访问一个到一个有lazy标记的结点,就顺便将它的lazy标记传播到下一层

    #include <cstdio>
    // #include <cstdlib>
    using namespace std;
    #define N 100000+5
    typedef long long ll;
    ll arr[N];
    ll tree[N<<2];
    ll lazy[N<<2];
    
    void push_up(int root){ // 向上传播,更新根节点的值
        tree[root] = tree[root<<1] + tree[root<<1|1];
    }
    void push_down(int left,int right,int root){ // lazy标记向下传播
        if(lazy[root]){
            int mid = (left+right)>>1;
            int left_root = root<<1;
            int right_root = root<<1|1;
            tree[left_root] += lazy[root] * (mid-left+1); // 更新子结点的值,但根结点的值还未更新,还需要push_up操作
            tree[right_root] += lazy[root] * (right-mid);
            lazy[left_root] += lazy[root]; // lazy标记向下传播
            lazy[right_root] += lazy[root];
            lazy[root] = 0;
        }
    }
    void build_tree(int left,int right,int root){
        if(left == right){
            tree[root] = arr[left];
        }else{
            int mid = left+right>>1;
            build_tree(left,mid,root<<1);
            build_tree(mid+1,right,root<<1|1);
            push_up(root);
        }
    }
    
    void update(int left,int right,int root,int update_left,int update_right,ll delta){
        if(update_left <= left && update_right >= right){ // 更新区间包含当前区间
            tree[root] += delta * (right-left+1); 
            lazy[root] += delta;
        }else{ // 更新区间不能包含当前区间
            int mid = (left+right)>>1;
            push_down(left,right,root);
            if(update_left <= mid){ // 在左子树中存在更新区间
                update(left,mid,root<<1,update_left,update_right,delta);
            }
            if(update_right > mid){ // 在右子树中存在更新区间
                update(mid+1,right,root<<1|1,update_left,update_right,delta);
            }
            push_up(root);
        }
    }
    
    ll query(int left,int right,int root,int query_left,int query_right){
        if(query_left <= left && query_right >= right){
            return tree[root];
        }else{
            push_down(left,right,root);
            int mid = (left+right)>>1;
            ll ans = 0;
            if(query_left <= mid){
                ans += query(left,mid,root<<1,query_left,query_right);
            }
            if(query_right > mid){
                ans += query(mid+1,right,root<<1|1,query_left,query_right);
            }
            return ans;
        }
    }
    int main(){
        int n,q;
        int l,r;
        ll delta;
        char cmd[5];
        scanf("%d%d",&n,&q);
        for(int i = 1; i <= n; i++){
            scanf("%lld",&arr[i]);
        }
        build_tree(1,n,1);
        while(q--){
            scanf("%s",cmd);
            if(cmd[0] == 'Q'){
                scanf("%d%d",&l,&r);
                printf("%lld
    ",query(1,n,1,l,r));
            }else{
                scanf("%d%d%lld",&l,&r,&delta);
                update(1,n,1,l,r,delta);
            }
        }
        // system("pause");
        return 0;
    }
    
    ---- suffer now and live the rest of your life as a champion ----
  • 相关阅读:
    第五次实验作业
    第四次作业
    java三
    java作业二
    java作业一
    作业11
    作业10
    作业9
    作业8
    作业7
  • 原文地址:https://www.cnblogs.com/popodynasty/p/13889804.html
Copyright © 2011-2022 走看看