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

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;
	 }


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值