码迷,mamicode.com
首页 > 其他好文 > 详细

模版_线段树

时间:2018-06-02 21:31:45      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:ons   线段树   区间   return   描述   pre   oid   query   else   

线段树模版之——区间修改与求和

题目描述:
给出数的个数n以及操作数q:
对于q:
1 x y z 令区间[x, y]增加z
2 x y 求区间和

#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const int maxn=1e5+10;
int n, q;
LL a[maxn];
LL sum[maxn<<2], li[maxn<<2];

void _push_up(int rt) {
    sum[rt]=sum[rt<<1]+sum[(rt<<1)|1];
}//向上更新,求区间和

void _setup(int l, int r, int rt) {
    li[rt]=0;
    if(l==r){
        sum[rt]=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    _setup(l, mid, rt<<1);
    _setup(mid+1, r, (rt<<1)|1);
    _push_up(rt);
}//建树

void _push_down(int rt, int m) {
    if(li[rt]) {
        li[rt<<1]+=li[rt];
        li[(rt<<1)|1]+=li[rt];
        sum[rt<<1]+=li[rt]*(m-(m>>1));
        sum[(rt<<1)|1]+=li[rt]*(m>>1);
        li[rt]=0;
    }
}//将li标记向下更新,传递给小区间

void _add(int x, int y, LL z, int l ,int r, int rt) {
    if(x<=l && y>=r) {
        li[rt]+=z;
        sum[rt]+=z*(r-l+1);
        return ;
    }
    _push_down(rt, r-l+1); //边算边更新,节省复杂度
    int mid=(l+r)>>1;
    if(x<=mid) _add(x, y, z, l, mid, rt<<1);
    if(y>mid) _add(x, y, z, mid+1, r, (rt<<1)|1);
    _push_up(rt);
}

LL _query(int x, int y, int l, int r, int rt) {
    if(x<=l && y>=r) {
        return sum[rt];
    }
    _push_down(rt, r-l+1); //求和时再顺便更新一次
    int mid=(l+r)>>1;
    LL ans=0;
    if(x<=mid) ans+=_query(x, y, l, mid, rt<<1);
    if(y>mid) ans+=_query(x, y, mid+1, r, (rt<<1)|1); //‘夹‘区间
    return ans;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=1; i<=n; i++) {
        scanf("%lld", a+i);
    }
    _setup(1, n, 1);
    for(int i=0; i<q; i++) {
        int ls;
        scanf("%d", &ls);
        if(ls==1) {
            int x, y;
            LL z;
            scanf("%d%d%lld", &x, &y, &z);
            _add(x, y, z, 1, n, 1);
        } else if(ls==2) {
            int x, y;
            scanf("%d%d", &x, &y);
            printf("%lld\n", _query(x, y, 1, n ,1));
        }
    }
    return 0;
}

有很多代码使用结构体实现线段树,不过我不太习惯用结构体来实现,因为有时候看到一堆点很难受...

模版_线段树

标签:ons   线段树   区间   return   描述   pre   oid   query   else   

原文地址:https://www.cnblogs.com/normaldisk/p/9126858.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!