【POJ No. 3468】简单的整数问题 A Simple Problem with Integers
【题意】
有N 个整数A 1, A 2, …, AN ,需要对其进行两种操作,一种操作是对给定区间中的每个数都添加一个给定的数,另一种操作是查询给定区间中数的总和。
【输入输出】
输入:
第1行包含两个数N 和Q (1≤N ,Q ≤105 );第2行包含N 个数,为A 1 , A 2 , …, AN 的初始值(-109 ≤Ai ≤109 );接下来的Q 行,每行都表示一种操作,“C a b c ”表示将Aa , Aa +1 ,…, Ab 中的每一个数都加c (-104 ≤c ≤104 ),“Q a b ”表示查询Aa , Aa +1 , …, Ab 的总和。
输出:
对每个查询,都单行输出区间和的值。
【样例】
提示: 总和可能超过32位整数的范围。
【思路分析】
本题有区间更新和区间查询两种操作。
【算法设计】
① 创建线段树,每个节点都存储区间信息[l , r ]及区间和val。
② 区间查询,在查询区间和的过程中若有懒标记则下传。
③ 区间更新,先查找区间,再更新区间和并打懒标记,在查找过程中若有懒标记则下传。
【算法实现】
#include<cstdio>
#include<algorithm>
#define N 100010
#define ll long long
using namespace std;
struct node{
int l,r;
ll val,lazy;
}t[N<<2];
int n,m,l,r;
ll x;
char c[2];
void build(int x,int l,int r){//建树
t[x].l=l;t[x].r=r;
if(l==r){
scanf("%lld",&t[x].val);
return;
}
int mid=(l+r)>>1;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
t[x].val=t[x*2].val+t[x*2+1].val;
}
void pushdown(int x){//下传标记
if(t[x].lazy){
t[x*2].lazy+=t[x].lazy;
t[x*2].val+=t[x].lazy*(t[x*2].r-t[x*2].l+1);
t[x*2+1].lazy+=t[x].lazy;
t[x*2+1].val+=t[x].lazy*(t[x*2+1].r-t[x*2+1].l+1);
t[x].lazy=0;
}
}
void update(int x,int l,int r,ll num){//区间修改
if(t[x].l==l&&t[x].r==r){
t[x].val+=num*(t[x].r-t[x].l+1);
t[x].lazy+=num;
return;
}
pushdown(x);//下传懒标记
int mid=(t[x].l+t[x].r)>>1;
if(r<=mid)
update(x*2,l,r,num);
else if(l>mid)
update(x*2+1,l,r,num);
else update(x*2,l,mid,num),update(x*2+1,mid+1,r,num);
t[x].val=t[x*2].val+t[x*2+1].val;
}
ll query(int x,int l,int r){//区间查询
if(t[x].l==l&&t[x].r==r)
return t[x].val;
pushdown(x);
int mid=(t[x].l+t[x].r)>>1;
if(r<=mid)
return query(x*2,l,r);
else if(l>mid)
return query(x*2+1,l,r);
else return query(x*2,l,mid)+query(x*2+1,mid+1,r);
}
int main(){
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i=1;i<=m;i++){
scanf("%s %d %d",c,&l,&r);
if(c[0]=='Q')
printf("%lld\n",query(1,l,r));
else{
scanf("%lld",&x);
update(1,l,r,x);
}
}
return 0;
}