POJ-3468 A Simple Problem with Integers

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.

Source

        题目大意大概是给你n个整数,然后对其做m次操作,操作方法有两种:Q:返回区间中所有整数的和;C:对区间x~y进行修改,将里面的所有值修改为z。数据范围1<=n,q<=1e5,-1e9<=ai<=1e9,-1e4<=c<=1e4。这个题目是很典型的线段树的区间点修改,区间求和。如果每修改一次就对区间整体进行一次值的变换时间复杂度太高,所以这里要用上lazy思想,将每次修改的地方记录下来,当下次对该处进行操作的时候再对其进行修改,否则就放着不动就好了,以求减小代码的时间复杂度。
以下贴上萌新喵的代码,各位巨佬不喜勿喷:
#include<cstdio>
using namespace std;
typedef long long LL;    ///因为a的初始范围是±1e9,为了避免后续操作导致a超范围,所以这里直接上longlong

int a[100005];

struct trees{
    int left,right,mid;
    LL sum,mark;    ///记录该父节点或者子叶节点的值和是否进行了操作
}tree[1000050];

void build(int x,int y,int num){    ///建树
    tree[num].left=x;
    tree[num].right=y;
    tree[num].mid=(x+y)>>1;
    tree[num].mark=0;    ///mark==0表示当前节点并未被操作
    if(x==y){
        tree[num].sum=a[x];
        return ;
    }
    int mid=(x+y)>>1;
    build(x,mid,num<<1);
    build(mid+1,y,(num<<1)+1);
    tree[num].sum=(tree[num<<1].sum+tree[(num<<1)+1].sum);
}

LL query(int x,int y,int num){    ///区间查询,返回x~y区间的和
    if(tree[num].left==x&&tree[num].right==y){
        return tree[num].sum+tree[num].mark*(LL)(y-x+1);
    }    ///当刚好是x~y这个区间时,mark继续可以不用变动
    if(tree[num].mark!=0){    ///当mark不为0时,对该节点的子节点的mark值进行操作,使之加上当前节点的mark值
        tree[num<<1].mark+=tree[num].mark;
        tree[(num<<1)+1].mark+=tree[num].mark;
        tree[num].sum+=(LL)(tree[num].right-tree[num].left+1)*tree[num].mark;
        tree[num].mark=0;    ///当前节点的mark清零
    }
    if(tree[num].mid>=y){
        return query(x,y,num<<1);
    }
    else if(tree[num].mid<x){
        return query(x,y,(num<<1)+1);
    }
    else {
        return query(x,tree[num].mid,num<<1)+query(tree[num].mid+1,y,(num<<1)+1);
    }
}

void update(int x,int y,int val,int num){    ///x~y区间修改
    if(tree[num].left==x&&tree[num].right==y){    ///当刚好是该区间时,将该节点的mark值赋值为val,并跳出
        tree[num].mark+=val;
        return ;
    }
    tree[num].sum+=(LL)val*(y-x+1);    ///如果该节点的区间大于说需要查找的区间,直接将该节点的sum进行加
    if(tree[num].mid>=y){
        update(x,y,val,num<<1);
    }
    else if(tree[num].mid<x){
        update(x,y,val,(num<<1)+1);
    }
    else{
        update(x,tree[num].mid,val,num<<1);
        update(tree[num].mid+1,y,val,(num<<1)+1);
    }
}

int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        int i;
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        build(1,n,1);
        int x,y,key;
        while(m--){
            char str[105];
            scanf("%s",&str);
            if(str[0]=='Q'){
                scanf("%d%d",&x,&y);
                printf("%lld\n",query(x,y,1));
            }
            else if(str[0]=='C'){
                scanf("%d%d%d",&x,&y,&key);
                update(x,y,key,1);
            }
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值