poj3468 A Simple Problem with Integers

A Simple Problem with Integers

Time Limit: 5000MS

 

Memory Limit: 131072K

Case Time Limit: 2000MS

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 a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" 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 <cstring>

#include <cstdio>

#include <algorithm>

using namespace std;

#define N 100008

#define lid (id<<1)//

#define rid (lid|1)//

typedef long long LL;

struct node

{

    int l,r;//左右边界

    LL sum;//表示的和

    int lazy;//延迟标记

}tr[N*4];

LL a[N];

 

void push_up(int id)//向上传递

{

    tr[id].sum = tr[lid].sum + tr[rid].sum;//一个结点的值等于它左右两边的和

}

 

void push_down(int id)//向下分解

{

    int m=tr[id].r-tr[id].l+1;//类似这个结点的长度

    if(tr[id].lazy)//延迟标记不为0

    {

        tr[lid].lazy+=tr[id].lazy;//延迟标记传给左边

        tr[rid].lazy+=tr[id].lazy;//延迟标记传给右边

        tr[lid].sum+=(LL)tr[id].lazy*(m-(m>>1));

        //左边的值等于它本身加上 添加的值乘长度的一半(也可以理解为它本身的长度)

        tr[rid].sum+=(LL)tr[id].lazy*(m>>1);

        //右边同理 只不过是剩下的一半

        tr[id].lazy=0;//注意 分解之后 延迟标记一定要变回0

    }

}

void build(int l,int r,int id)//从上到下建立一棵树

{

    tr[id].l = l; tr[id].r = r;//左右边界赋值

    tr[id].sum = 0;//和赋值

    tr[id].lazy = 0;//延迟标记清零

    if( l == r )

    {

        tr[id].sum=a[l];

        return ;//结束条件别忘了

    }

 

    int mid=(tr[id].l+tr[id].r)>> 1;//中点

    build(l,mid,lid);//左边

    build(mid+1,r,rid);//右边

    push_up(id);//向上传递

}

 

void updata(int a,int b,int id,int val)//更新区间内的值

{

    if(tr[id].l>=a&&tr[id].r<=b)//恰好是要更新的范围

    {

        tr[id].lazy+=val;//延迟标记加上更新值

        tr[id].sum+=(LL)val*(tr[id].r-tr[id].l+1);//此结点值变为它本身加上它所包含的长度

        return ;

    }

    else

    {

        push_down(id);//向下分解

        int mid=(tr[id].l+tr[id].r)>> 1;//中点

        if(a>mid)//区间起点大于中点

        {

            updata(a,b,rid,val);//全部在右边 更新右

        }

        else if(b<=mid)//区间终点小于等于终点

        {

            updata(a,b,lid,val);//全部在左边 更新左

        }

        else//两边都有

        {

            updata(a,b,rid,val);

            updata(a,b,lid,val);

        }//都更新

    }

    push_up(id);//向上传递

}

 

LL query(int a,int b,int id,int val)//查询区间值

{

    if(tr[id].l>=a&&tr[id].r<=b)//恰好是要查询的区间

        return tr[id].sum;//直接返回值

    else

    {

        push_down(id);//查询时也别忘了分解

        int mid=(tr[id].l+tr[id].r)>> 1;//中点

        if(a>mid)//全在右 查询右

        {

            return query(a,b,rid,val);

        }

        else if(b<=mid)//全在左 查询左

        {

            return query(a,b,lid,val);

        }

        else//都有 返回两边的和

        {

            return query(a,b,rid,val)+query(a,b,lid,val);

        }

    }

}

 

int main()

{

    int n,t;

    while(cin>>n>>t)

    {

        for(int i=1;i<=n;i++)

        {

            cin>>a[i];

        }

        build(1,n,1);

        while(t--)

        {

            char op;

            cin>>op;

            int a,b,val;

            if(op=='C')

            {

                cin>>a>>b>>val;

                updata(a,b,1,val);

            }

            else

            {

                cin>>a>>b;

                printf("%I64d\n",query(a,b,1,val));

            }

        }

    }

    return 0;

}

注意:强制类型转换。中间的地方也会超出int范围。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值