POJ 3468_A Simple Problem with Integers(线段树)

题意:

给定序列及操作,求区间和。

分析:

线段树,每个节点维护两个数据:

  • 该区间每个元素所加的值
  • 该区间元素和

可以分为“路过”该区间和“完全覆盖”该区间考虑。

代码:

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
//[l,r)
const int maxn = 300005;
ll sum[maxn], add[maxn];
int v[maxn];
void update(int a, int b, int x, int k, int l, int r)
{
    if(a <= l && r <= b) add[k] += x;
    else if(l < b && a < r){
        sum[k] += (min(r,b) - max(l,a))*x;
        update(a, b, x, k * 2 + 1, l, (l+r)/2);
        update(a, b,x, k * 2 + 2, (l+r)/2, r);
    }
}
ll query(int a, int b, int k, int l, int r)
{
    if(a >= r|| b <= l) return 0;
    else if(a <= l&&r <= b) return (r - l) * add[k] + sum[k];
    else {
        ll res = (min(b,r)-max(a,l)) * add[k];
        res += query(a, b, k * 2 + 1, l, (l+r)/2);
        res += query(a, b, k * 2 + 2, (l + r)/2, r);
        return res;
    }
}
int main (void)
{
    int n, q;scanf("%d%d",&n,&q);
    int a, b, c;
    for(int i = 0; i < n; i++){
        scanf("%d",&v[i]);
        update(i, i + 1, v[i], 0, 0, n);
    }
    for(int i = 0; i < q; i++){
        getchar();
        if(getchar()=='C'){
            scanf("%d%d%d", &a, &b, &c);
            update(a-1, b, c, 0 , 0, n);
        }else{
            scanf("%d%d",&a, &b);
            printf("%I64d
",query(a - 1, b, 0, 0, n));
        }
    }
    return 0;
}

写的时候还是磕磕绊绊,看来当初学的时候理解的并不好

原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758797.html