zoukankan      html  css  js  c++  java
  • 线段树 洛谷P3372

    题目描述

    如题,已知一个数列,你需要进行下面两种操作:

    1.将某区间每一个数加上x

    2.求出某区间每一个数的和

    输入输出格式

    输入格式:

    第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

    第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

    接下来M行每行包含3或4个整数,表示一个操作,具体如下:

    操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

    操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

    输出格式:

    输出包含若干行整数,即为所有操作2的结果。

    输入输出样例

    输入样例#1:
    5 5
    1 5 4 2 3
    2 2 4
    1 2 3 2
    2 3 4
    1 1 5 1
    2 1 4
    输出样例#1:
    11
    8
    20

    转载一篇不错的线段树文章:http://blog.csdn.net/zearot/article/details/48299459

    进行区间更新、区间查询,时间复杂度都是 O(logN) 的一种数据结构。

    代码:

    #include <iostream>
    #include <cstring>
    #define LL long long 
    using namespace std;
    
    const int MAX = 100005;
    
    int n, m;
    LL a[MAX];
    LL tree[4*MAX];        //每个结点(区间)对应的和是多少
    LL mark[4*MAX];        //懒标记 
    
    int buildTree(int root, int l, int r);        //建树 
    LL add(int root, int l, int r, int L, int R, LL num);        //区间 [L, R] 中的每个数增加 num。当前结点所对应的区间为 [l, r]。返回值为该区间和一共增加了多少。 
    LL query(int root, int l, int r, int L, int R);                //返回区间 [L, R] 的和是多少。当前区间为 [l, r] 
    
    int main(){
    //    freopen("input.txt", "r", stdin);
        
        scanf("%d%d", &n, &m);
        for(int i=1; i<=n; i++){
            scanf("%lld", &a[i]);
        }
        
        buildTree(1, 1, n);
        for(int i=1; i<=m; i++){
            int opt, x, y;
            LL z;
            scanf("%d%d%d", &opt, &x, &y);
            if(opt == 1){
                scanf("%lld", &z);
                add(1, 1, n, x, y, z);
            }else{
                printf("%lld
    ", query(1, 1, n, x, y));
            }
        }
        
        return 0;
    }
    
    int buildTree(int root, int l, int r){
        mark[root] = 0;
        if(l == r){
            tree[root] = a[l];
            return a[l];
        }
        int mid = (l + r) / 2;
        tree[root] = buildTree(2*root, l, mid) + buildTree(2*root+1, mid+1, r);
        return tree[root];
    }
    
    LL add(int root, int l, int r, int L, int R, LL num){
        if(l > R || r < L || l > r){        //不可能有交集 
            return 0;
        }
        if(l >= L && r <= R){                    //当前区间是要求的区间的一部分 
            mark[root] += num * (r - l + 1);    //进行懒标记,当前区间的和要增加这么多(当前区间的子区间在查询时,如果有需要再进行更新) 
            return num * (r - l + 1);
        }
        int mid = (l + r) / 2;
        LL addNum1 = add(2*root, l, mid, L, R, num);
        LL addNum2 = add(2*root+1, mid+1, r, L, R, num);    //左、右区间一共增加了多少
        tree[root] += addNum1 + addNum2;
        return addNum1+addNum2; 
    }
    
    LL query(int root, int l, int r, int L, int R){
        if(l > R || r < L || l > r){        //不可能有交集 
            return 0;
        }
        if(l >= L && r <= R){            //为要求区间的一部分 
            return tree[root] + mark[root];
        }
        int mid = (l + r) / 2;
        if(mark[root] != 0){            //要将懒标记清零了,并且向下推 
            LL num = mark[root] / (r - l + 1);
            mark[2*root] += num * (mid - l + 1);
            mark[2*root+1] += num * (r - mid);
            tree[root] += mark[root];
            mark[root] = 0;
        }
        return query(2*root, l, mid, L, R) + query(2*root+1, mid+1, r, L, R);
    }
  • 相关阅读:
    DockerFile 解析
    Docker 容器数据卷
    Docker 镜像
    Docker 常用命令
    Docker 安装
    vue全站式笔记
    接口环境配置
    前端跨域的三种方式
    vue+axios 模拟后台返回数据的三种方式:本地创建json、easymock平台、mockjs
    cookie、sessionStorage与localStorage是什么?
  • 原文地址:https://www.cnblogs.com/lighter-blog/p/7445646.html
Copyright © 2011-2022 走看看