A Simple Problem with Integers (POJ_3468) 线段树+区间更新


A Simple Problem with Integers
Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 84588   Accepted: 26203
Case Time Limit: 2000MS

Description

You have N integers, A1A2, ... , 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 A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+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.




题目大意:给出n个数,对这些树进行区间更新和查询操作

解题思路:利用线段树区间更新,注意区间更新时当节点区间全部包含于待更新区间时,不再对其下节点更新,而把更新值c存储在add中,当线段树的平衡被破坏时,再将值向下更新。

代码如下:




#include"iostream"
#include"cstdio"
#define ll __int64
using namespace std;
//线段树的最大节点数
const ll maxn=110000; 
//线段数定义 
struct Tree{
	ll l,r,sum,add;
	ll getmid(){	//返回线段的中点 
		return (l+r)>>1;
	}
}tree[4*maxn];
//向上一层推
void pushup(ll x){
	ll tmp=2*x;
	tree[x].sum=tree[tmp].sum+tree[tmp+1].sum;
} 
//向下一层推
void pushdown(ll x){
	ll tmp=2*x;
	tree[tmp].add+=tree[x].add;
	tree[tmp+1].add+=tree[x].add;
	tree[tmp].sum+=tree[x].add*(tree[tmp].r-tree[tmp].l+1);
	tree[tmp+1].sum+=tree[x].add*(tree[tmp+1].r-tree[tmp+1].l+1);
	tree[x].add=0;
} 
//构建线段树
void Build(ll l,ll r,ll x){
	tree[x].l=l;
	tree[x].r=r;
	tree[x].add=0;
	if(tree[x].l==tree[x].r){	//叶子节点 
		scanf("%I64d",&tree[x].sum);
		return ;
	}
	ll mid=tree[x].getmid();
	ll tmp=2*x;
	Build(l,mid,tmp);	//向左子树递归 
	Build(mid+1,r,tmp+1);	//向右子树递归 
	pushup(x);	//在回溯时向上推 
}
//区间更新
void Updata(ll l,ll r,ll x,ll c){	//所更新区间【l,r】,增加值c,当前节点x 
	if(tree[x].l>r||tree[x].r<l)	//节点包含区间,不在更新区间内 
		return ;
	if(l<=tree[x].l&&tree[x].r<=r){	//节点包含区间包含于更新区间 
		tree[x].add+=c;
		tree[x].sum+=c*(tree[x].r-tree[x].l+1);
		return ;
	}
	if(tree[x].add!=0)
		pushdown(x);	//在抵达新一轮更新区间前,将之前积攒的add向下更新
	ll tmp=2*x;
	Updata(l,r,tmp,c); 
	Updata(l,r,tmp+1,c);
	pushup(x);
}  
//区间查询
ll ans;		//存储查询答案 
void Query(ll l,ll r,ll x){	//【l,r】为当前查询区间,x为当前节点 
	if(tree[x].l>r||tree[x].r<l)			//节点包含区间不在查询区间
		return ;
	if(l<=tree[x].l&&tree[x].r<=r){			//节点区间包含于查询区间 
		ans+=tree[x].sum;
		return ;
	}
	if(tree[x].add!=0)
		pushdown(x);	//在抵达询问区间前,将之前积攒的add向下更新
	ll mid=tree[x].getmid();
	ll tmp=2*x;
	if(r<=mid)			//当前查询区间在节点的左半区间 
		Query(l,r,tmp);
	else if(l>mid)		//当前查询区间在节点的右半区间
		Query(l,r,tmp+1); 
	else{				//查询区间分布在节点的左右区间 
		Query(l,mid,tmp);
		Query(mid+1,r,tmp+1);
	}
} 
//主函数
int main(){
	ll n,q;
	while(scanf("%I64d%I64d",&n,&q)!=EOF){
		Build(1,n,1);
		char ch;
		while(q--){
			getchar();
			ch=getchar();
			ll x,y,c;
			if(ch=='C'){
				scanf("%I64d%I64d%I64d",&x,&y,&c);
				Updata(x,y,1,c);
			}
			else{
				scanf("%I64d%I64d",&x,&y);
				ans=0;
				Query(x,y,1);
				printf("%I64d\n",ans);
			}	
		}
	}
	return 0;
}



你可能感兴趣的:(A Simple Problem with Integers (POJ_3468) 线段树+区间更新)