poj 3468 A Simple Problem with Integers(线段树的区间更新与求和)

A Simple Problem with Integers

题目连接:http://poj.org/problem?id=3468

题目大意:给出一个数组,要求对一个区间所有的值加某一个数或者计算某一区间所有值的和。

题目思路:利用线段树处理,具体见代码

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 100010
struct Node{
    int L;
    int R;
    long long add;///表示左右结点的区间都要增加add
    long long sum;///该节点在更新之前的值
}tree[4*N];

///建树
void BuildTree(int root,int l,int r){
    tree[root].L=l;
    tree[root].R=r;
    tree[root].add=0;
    tree[root].sum=0;
    if(l==r){
        int a;
        scanf("%d",&a);
        tree[root].sum=a;///根节点的sum就为本身
        return ;
    }
    int mid=(l+r)/2;
    BuildTree(2*root,l,mid);
    BuildTree(2*root+1,mid+1,r);
    tree[root].sum=tree[2*root].sum+tree[2*root+1].sum;///父节点的sum等于两子节点的和
}


///区间更新
void Update(int root,int s,int e,long long v){
    if(tree[root].L==s&&tree[root].R==e){
        tree[root].add+=v;///因为区间的数每个都要加v,所有直接令add+v。。此时子节点还未更新
        return ;
    }
    tree[root].sum+=v*(e-s+1);///区间不匹配,不能每个都加,则将要加的数总和直接赋给sum
    int mid=(tree[root].L+tree[root].R)/2;
    if(e<=mid) Update(2*root,s,e,v);
    else if(s>mid) Update(2*root+1,s,e,v);
    else {
        Update(2*root,s,mid,v);
        Update(2*root+1,mid+1,e,v);
    }

}

///区间求和
long long QuerySum(int root,int s,int e){
    if(tree[root].L==s&&tree[root].R==e){
        return tree[root].sum+(e-s+1)*tree[root].add;///区间匹配,结果为结点本身的sum加上区间还有每个数都要加的add
    }
    int mid=(tree[root].L+tree[root].R)/2;
    ///更新子节点
    tree[root].sum+=(tree[root].R-tree[root].L+1)*tree[root].add;
    Update(2*root,tree[root].L,mid,tree[root].add);
    Update(2*root+1,mid+1,tree[root].R,tree[root].add);
    tree[root].add=0;

    if(e<=mid) return QuerySum(2*root,s,e);
    else if(s>mid)  return QuerySum(2*root+1,s,e);
    else {
        return QuerySum(2*root,s,mid)+QuerySum(2*root+1,mid+1,e);
    }
}

int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    BuildTree(1,1,n);
    while(q--){
        char s[4];
        scanf("%s",s);
        if(s[0]=='Q'){
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%I64d\n",QuerySum(1,a,b));
        }
        else{
            int a,b;
            long long c;
            scanf("%d%d%I64d",&a,&b,&c);
            Update(1,a,b,c);
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值