poj 3468(线段树) A Simple Problem with Integers


A - A Simple Problem with Integers
Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u

Description

You have N integers, A1A2, ... , 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 A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C abc" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q ab" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.

今天开始学习线段树,这种题就是比较裸的题了,于是马上制作自己最喜欢用的板子,现在成型辣,虽说也是借鉴别人哒~

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <string>
#include <cstring>
#include <vector>
using namespace std;
const int MAXN=100000+5;
int n,m;
struct node
{
    int l,r;
    long long sum;
    long long inc;
}tree[MAXN<<2];
void build(int i,int l,int r)//建树,没什么好说的,类似递归
{
    tree[i].l=l;
    tree[i].r=r;
    tree[i].inc=0;//增量初始化为0
    if(l==r)//如果更新到底部就附上值
    {
        scanf("%lld",&tree[i].sum);
        return ;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;//孩子建完要更新父亲结点值
}
void add(int i,int l,int r,long long c)
{
    if(tree[i].l==l&&tree[i].r==r)//更新到段就可以,暂时不向下更新,只加在inc上
    {
        tree[i].inc+=c;
        return ;
    }
    //如果还没有到达所要更新的区间,那么上面的持续向下更新。
    tree[i].sum+=c*(r-l+1);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)add(i<<1,l,r,c);
    else if(l>mid)add(i<<1|1,l,r,c);
    else
    {
        add(i<<1,l,mid,c);
        add(i<<1|1,mid+1,r,c);
    }
}
long long ask(int i,int l,int r)
{
    //询问操作
    if(tree[i].l==l&&tree[i].r==r)
    {
        return tree[i].sum+(r-l+1)*tree[i].inc;//找到了就返回
    }
    //如果要继续向下寻找,那么就需要先更新孩子结点,再寻找(也就是你询问到哪一层,就更新到哪一层)
    tree[i].sum+=(tree[i].r-tree[i].l+1)*tree[i].inc;
    int mid=(tree[i].l+tree[i].r)>>1;
    add(i<<1,tree[i].l,mid,tree[i].inc);
    add(i<<1|1,mid+1,tree[i].r,tree[i].inc);
    tree[i].inc=0;//赋值给0
    //继续寻找
    if(r<=mid)return ask(i<<1,l,r);
    else if(l>mid)return ask(i<<1|1,l,r);
    else
    {
        return ask(i<<1,l,mid)+ask(i<<1|1,mid+1,r);
    }
}


int main()
{
    int i;
    int l,r,c;
    char s[2];
    while(~scanf("%d%d",&n,&m))
    {
        build(1,1,n);
        while(m--)
        {
            scanf("%s",s);
            if(s[0]=='Q')
            {
                scanf("%d%d",&l,&r);
                printf("%lld\n",ask(1,l,r));
            }
            else
            {
                scanf("%d%d%d",&l,&r,&c);
                add(1,l,r,c);
            }
        }
    }

    return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值