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

OI模板——线段树(segment_tree)O(lg n)

时间:2015-09-12 18:59:09      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:

咱家越来越懒了,连解释都懒得去写了,主要思想就是把一个区间当作一个线段,然后不断的递归二分最后成为各个点,关键在于lazy_tag,当你正在处理的区间完全在目标操作区间时就可以用lazy来处理,不再递归下去,思想是这样的,想要会的话呢,应该先去照着打两遍,边打边理解,然后就可以自己打啦

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>

#define l(x) st[x].l
#define r(x) st[x].r
#define sum(x) st[x].sum
#define lazy(x) st[x].lazy

using namespace std;

typedef long long ll;

const int Size = 1e5 + 5;

struct segment_tree{
    int l,r;
    ll sum,lazy;
}st[Size << 2];

int a[Size];

void build(int,int,int);
void spread(int);
void change(int,int,int,int);
ll ask(int,int,int);

int main(){
    int n, q;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    build(1, 1, n);
    scanf("%d",&q);
    for (int i = 0; i < q; i++){
        int o,a, b, c;
        scanf("%d%d%d",&o,&a,&b);
        if (o==1){
            scanf("%d", &c);
            change(1, a, b, c);
        }
        else    cout << ask(1,a,b) << endl;//printf("%I64d\n", ask(1, a, b));
    }
    return 0;
} 

void build(int x,int l,int r){
    l(x) = l,r(x) = r;
    if (l == r){
        sum(x) = a[l];
        return ;
    }
    int mid = l + r >> 1;
    build(x << 1,l,mid);
    build(x << 1| 1,mid + 1,r);
    sum(x) = sum(x << 1) + sum(x << 1 | 1);
}

void spread(int x){
    if (lazy(x)){
        sum(x << 1) += lazy(x) * (r(x << 1) - l(x << 1) + 1);
        sum(x << 1 | 1) += lazy(x) * (r(x << 1 | 1) - l(x << 1 | 1) + 1);
        lazy(x << 1) += lazy(x);
        lazy(x << 1 | 1) += lazy(x);
        lazy(x) = 0;
    }
}

void change(int x,int l,int r,int delta){
    if (l <= l(x) && r >= r(x)){
        sum(x) += delta * (r(x) - l(x) + 1);
        lazy(x) += delta;
        return ;
    } 
    int mid = l(x) + r(x) >> 1;
    spread(x);
    if (l <= mid)     change(x << 1,l,r,delta);
    if (r > mid)    change(x << 1 | 1,l,r,delta);
    sum(x) = sum(x << 1) + sum(x << 1 | 1);
    return ;
}

ll ask(int x,int l,int r){
    if (l <= l(x) && r >= r(x))
        return sum(x);
    int mid = l(x) + r(x) >> 1;
    ll ans = 0;
    if (l <= mid)    ans += ask(x << 1,l,r);
    if (r > mid)    ans += ask(x << 1 | 1,l,r);
    return ans;
}

 

OI模板——线段树(segment_tree)O(lg n)

标签:

原文地址:http://www.cnblogs.com/GENEVE/p/4803335.html

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