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

【模板】线段树

时间:2018-08-13 19:44:20      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:std   一个   ++i   amp   数加   oid   lld   scanf   for   

题意简述

已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.求出某区间每一个数的和

代码

#include <cstdio>
using namespace std;
typedef long long ll;
ll n, m, opt, x, y, k;
ll a[400010], la[400010];
void push_up(ll x)
{
    a[x] = a[x << 1] + a[x << 1 | 1];
}
void push_down(ll x, ll len)
{
    a[x << 1] += la[x] * (len - (len >> 1));
    a[x << 1 | 1] += la[x] * (len >> 1);
    la[x << 1] += la[x];
    la[x << 1 | 1] += la[x];
    la[x] = 0;
}
void build(ll x, ll l, ll r)
{
    if (l == r)
    {
        scanf("%d", &a[x]);
        return;
    }
    ll mid = l + r >> 1;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
    push_up(x);
}
void add(ll x, ll l, ll r, ll l1, ll r1)
{
    if (l1 <= l && r <= r1)
    {
        a[x] += (r - l + 1) * k;
        la[x] += k;
        return;
    }
    if (la[x]) push_down(x, r - l + 1);
    ll mid = l + r >> 1;
    if (l1 <= mid) add(x << 1, l, mid, l1, r1);
    if (r1 >  mid) add(x << 1 | 1, mid + 1, r, l1, r1);
    push_up(x);
}
ll query(ll x, ll l, ll r, ll l1, ll r1, ll ans = 0)
{
    if (l1 <= l && r <= r1) return a[x];
    if (la[x]) push_down(x, r - l + 1);
    ll mid = l + r >> 1;
    if (l1 <= mid) ans += query(x << 1, l, mid, l1, r1);
    if (r1 >  mid) ans += query(x << 1 | 1, mid + 1, r, l1, r1);
    return ans;
}
int main()
{
    scanf("%lld%lld", &n, &m);
    build(1, 1, n);
    for (register ll i = 1; i <= m; ++i)
    {
        scanf("%lld", &opt);
        if (opt == 1)
        {
            scanf("%lld%lld%lld", &x, &y, &k);
            add(1, 1, n, x, y);
        }
        else
        {
            scanf("%lld%lld", &x, &y);
            printf("%lld\n", query(1, 1, n, x, y));
        }
    }
}

【模板】线段树

标签:std   一个   ++i   amp   数加   oid   lld   scanf   for   

原文地址:https://www.cnblogs.com/xuyixuan/p/9470176.html

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