您的位置:首页 > 编程语言 > C语言/C++

POJ 3468 A Simple Problem with Integers(线状树经典模型之lazy操作)

2016-04-21 19:48 519 查看
A Simple Problem with Integers
Crawling in process...Crawling failed

Time Limit:5000MS     Memory Limit:131072KB    64bit IO Format:%I64d & %I64u
     POJ
3468

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 numbersN 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 abc" means adding c to each of Aa, Aa+1, ... ,Ab. -10000 ≤
c ≤ 10000.

"Q ab" means querying the sum of Aa, Aa+1, ... ,Ab.

Output

You need to answer allQ 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. 

区间更新区间求和。

这里就要涉及到懒操作。注意的是lazy被更新的区间一定是当前的区间和已经更新完

>>AC代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int N,M;
ll b[101000];
struct zxs{
int l,r;
ll sum,lazy;
}tree[101000*4];
void build(int id,int l,int r){
tree[id].l=l;
tree[id].r=r;
tree[id].lazy=0;
if(l==r){
tree[id].sum=b[l];
return;}
int mid=(r+l)/2;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
}
void push_down(int id ){
if(tree[id].lazy==0)return ;//这个预判注意......
tree[id*2].sum+=tree[id].lazy*(tree[id*2].r-tree[id*2].l+1);
tree[id*2].lazy+=tree[id].lazy;
tree[id*2+1].sum+=tree[id].lazy*(tree[id*2+1].r-tree[id*2+1].l+1);
tree[id*2+1].lazy+=tree[id].lazy;
tree[id].lazy=0;
}

void update(int id,int x,int y,ll n){
if(tree[id].l>=x&&tree[id].r<=y){
tree[id].lazy+=n;
tree[id].sum+=n*(tree[id].r-tree[id].l+1);//这样才是对的
//也可以写成tree[id].sum+=n*(y-x+1);但这个从理解上来说是错的,改成这样也能AC,为什么?
//经过一番思考,终于得到答案:如果一开始tree[id].l==x&&tree[id].r==y那么这样加是等效的,肯定没有错
//如果一开始x,y的区间不满足上述条件,那么可以看见在update末尾是有一个
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum,也就是最终还有一次彻底的正确的更新,
因此也不会错,但是为了规范,一定得写成正确的tree[id].sum+=n*(tree[id].r-tree[id].l+1);
return;}
push_down(id);
int l=tree[id].l;
int r=tree[id].r;
int mid=(r+l)/2;
if(mid<x) update(id*2+1,x,y,n);
else if(y<=mid) update(id*2,x,y,n);
else {update(id*2,x,mid,n);
update(id*2+1,mid+1,y,n);
}
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
}
ll query(int id,int x,int y){
if(x<=tree[id].l&&tree[id].r<=y){return tree[id].sum;}
//刚开始写成x>=tree[id].l.......吐血WA。
push_down(id);
int l=tree[id].l;
int r=tree[id].r;
int mid=(l+r)/2;
if(y<=mid){return query(id*2,x,y);}
else if(x>mid){return query(id*2+1,x,y);}
else{
return query(id*2,x,mid)+query(id*2+1,mid+1,y);
}
}
int main(){
while(scanf("%d%d",&N,&M)!=EOF){
int x1,x2;
long long x3;
for(int i=1;i<=N;i++)
scanf("%lld",b+i);
//再次吐血,I写成l
build(1,1,N);
char s[10];
for(int i=0;i<M;i++){
scanf("%s",s);
if(s[0]=='Q'){
scanf("%d%d",&x1,&x2);
cout<<query(1,x1,x2)<<endl;}
else{
scanf("%d%d%lld",&x1,&x2,&x3);
//64位输出用%lld最方便了,不要写成%I64d不然等下I写成L又出bug了!
//细节决定成败!
update(1,x1,x2,x3);
}
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息