线段树模板POJ-3468

A Simple Problem with Integers

链接

Description

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.

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<stack>
#include<cstdio>
using namespace std;
typedef long long ll;
#define rep(i,x,y) for(register int i=x;i<=y;++i)
#define gc getchar()
template<class T>
inline void read(T&x) {
    x=0;
    char ch=gc;
    bool flag=0;
    while(ch<'0'||ch>'9')flag|=(ch=='-'),ch=gc;
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=gc;
    x=flag?-x:x;
}
const int maxn=100000+10;
int n,q;
ll val[maxn];
struct Node {
    ll sum,add;//sum:[l,r] 区间总和,add: 儿子区间要加的数
    //add只和儿子节点有关;
    int l,r;
} t[maxn*3];//*2的话,数据50w时过不了
void build(int i,int x,int y) {//建树
    t[i].add=0;
    t[i].l=x,t[i].r=y;
    if(x==y) {t[i].sum=val[x];return;}
    int m=(x+y)>>1;
    build(i<<1,x,m);
    build((i<<1)|1,m+1,y);
    t[i].sum=t[i<<1].sum+t[(i<<1)|1].sum;
}
inline void putdown(int i) {//将add下放到他的儿子里
    t[i<<1].sum+=t[i].add*(t[i<<1].r-t[i<<1].l+1);//这里也能说明sum是区间总和,而与add无关。
    //这里是乘t[i].add不是乘更新之后的t[i<<1].add,因为 //add只和儿子节点有关,t[i<<1].add是节点(i<<1)儿子们的
)    t[i<<1].add+=t[i].add;
    t[(i<<1)|1].sum+=t[i].add*(t[(i<<1)|1].r-t[(i<<1)|1].l+1);
    t[(i<<1)|1].add+=t[i].add;
    t[i].add=0;
}
ll sum(int i,int x,int y) {
    if(t[i].l>=x&&t[i].r<=y)return t[i].sum;
    if(t[i].add)putdown(i);//如果要查询儿子节点,则儿子加上add
    ll ans=0;
    int m=(t[i].r+t[i].l)>>1;
    if(x<=m)ans+=sum(i<<1,x,y);
    if(y>m)ans+=sum((i<<1)|1,x,y);
    return ans;
}
void add(int i,int x,int y,int a) {//区间x,y上加上a
    if(t[i].l>=x&&t[i].r<=y) {
        t[i].add+=a;//子节点都要加
        t[i].sum+=a*(t[i].r-t[i].l+1);//sum已更新,下次查询到该区间直接return sum;
        return;
    }
    if(t[i].add)putdown(i);//如果要更新子节点,得先把add下放给子节点。
    //不等价于下面两句。
    //a+=t[i].add;
	//t[i].add=0;
    int m=(t[i].r+t[i].l)>>1;
    if(x<=m)add(i<<1,x,y,a);
    if(y>m)add((i<<1)|1,x,y,a);
    t[i].sum=t[i<<1].sum+t[(i<<1)|1].sum;
}
int main() {
//    freopen("in.txt","r",stdin);
    read(n),read(q);
    rep(i,1,n)read(val[i]);
    build(1,1,n);
    char ch;
    int x,y,a;
    rep(i,1,q) {
        ch=getchar();
        if(ch=='Q') {
            read(x),read(y);
            printf("%lld\n",sum(1,x,y));
        } else {
            read(x),read(y),read(a);
            add(1,x,y,a);
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值