A Simple Problem with Integers POJ - 3468(线段树)

You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.
Output
You need to answer all Q commands in order. One answer in a line.

题目链接
参考题解

题意:N 个数 Q 个操作,Q a b 表示输出 [a,b] 区间内的和,C a b c 表示将 [a,b] 区间内所有的值都加上 c

思路:线段树模板题,区间更新+区间查询,注意使用 long long,emmm,最后查询的时候写成int,忘记改成longlong,wa到哭了。这里就是想记录一下,在记录lazy标记的时候,一定要先把整个区间的值都加到这个节点上。因为,你这样如果要往下更新的话,下面的区间也会这样更新,最后再pushup的时候才能得到一个准确的值,如果不当时就更改然后pushup,等查询的时候往下推状态的时候,这样是不行的,因为你不知道这部分是不是后来其中某一部分又有了修改。但在查询的时候,直接返回了,这样就产生了错误结果。(如看不懂就忽略了吧,记住下面板子就好了)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAX_SIZE = 1e5+5;
LL sum[MAX_SIZE<<2], lazy[MAX_SIZE<<2], data[MAX_SIZE];

void Push_Up(int Root)
{
    sum[Root] = sum[Root<<1] + sum[Root<<1|1];
    return ;
}

void Push_Down(int left, int right, int Root)
{
    if(lazy[Root] == 0) return ;    //如果这个节点没有修改,不需操作
    int mid = (left+right)>>1;
    lazy[Root<<1] += lazy[Root];
    lazy[Root<<1|1] += lazy[Root];
    sum[Root<<1] += lazy[Root]*(mid-left+1);
    sum[Root<<1|1] += lazy[Root]*(right-mid);
    lazy[Root] = 0;
    return ;
}

void Build(int left, int right, int Root)
{
    lazy[Root] = 0;
    if(left == right)
    {
        sum[Root] = data[left];
        return ;
    }
    int mid = (left+right)>>1;
    Build(left, mid, Root<<1);
    Build(mid+1, right, Root<<1|1);
    Push_Up(Root);
    return ;
}

void Section_Change(int Left, int Right, int left, int right, int Root, LL value)
{
    if(Left <= left && Right >= right)
    {
        lazy[Root] += value;
        sum[Root] += value*(right-left+1);
        return ;
    }
    Push_Down(left, right, Root);
    int mid = (left+right)>>1;
    if(Left <= mid) Section_Change(Left, Right, left, mid, Root<<1, value);
    if(Right > mid) Section_Change(Left, Right, mid+1, right, Root<<1|1, value);
    Push_Up(Root);  //一定要pushup,否则结果不对,因为下面可能会有变动
    return ;
}

LL Section_Query(int Left, int Right, int left, int right, int Root)
{
    if(Left <= left && Right >= right)  return sum[Root];
    Push_Down(left, right, Root);   //先把当前节点的状态推到孩子上
    int mid = (left+right)>>1;
    LL ans = 0;
    if(Left <= mid) ans += Section_Query(Left, Right, left, mid, Root<<1);
    if(Right > mid) ans += Section_Query(Left, Right, mid+1, right, Root<<1|1);
    return ans;
}

int main()
{
    int N, Q;
    cin >> N >> Q;
    for(int i = 1; i <= N; i++) scanf("%lld", &data[i]);
    Build(1, N, 1);
    for(int i = 0; i < Q; i++)
    {
        getchar();
        char op = getchar();
        int a, b;
        LL c;
        if(op == 'C')   scanf("%d%d%lld", &a, &b, &c);
        else    scanf("%d%d", &a, &b);
        if(op == 'C')   Section_Change(a, b, 1, N, 1, c);
        else    c = Section_Query(a, b, 1, N, 1);
        if(op == 'Q')   printf("%lld\n", c);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值