首页 > 代码库 > POJ A Simple Problem with Integers 【线段树,区间更新】

POJ A Simple Problem with Integers 【线段树,区间更新】

题意:你有N个整数,A1,A2,…,一个。你需要处理两种类型的操作。一种类型的操作是添加了一些给定的数字,每个数字在一个给定的时间间隔。另一种是在给定的时间间隔要求数量的总和。 

难点:主要是lazy标记,不好弄懂, 其实lazy标记就是当前改变的值不全部更新,等到用的时候再更新,这样就节省了好多时间。 

题目链接:http://poj.org/problem?id=3468

代码:

#include<stdio.h>
#include<string.h>
#define MAXN 100005
#define LC l, m, rt<<1
#define RC m+1, r, rt<<1|1 
#define LL __int64
LL sum[MAXN<<2], add[MAXN<<2];//add数组就是暂时储存要增加的
void pushup(int rt)
{
	sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt, int m)//这个是难点,理解了这个这道题就差不多了
{
	if(add[rt]){
		add[rt<<1] += add[rt];
		add[rt<<1|1] += add[rt];
		sum[rt<<1] += add[rt]*(m-(m>>1));
		sum[rt<<1|1] += add[rt]*(m>>1);
		add[rt] = 0;
	}
}
void creat(int l,int r,int rt) {
	add[rt] = 0;
	if (l == r) {
		scanf("%I64d",&sum[rt]);
		return ;
	}
	int m = (l + r) >> 1;
	creat(LC);
	creat(RC);
	pushup(rt);
}
void update(int le, int ri, int num, int l, int r, int rt)
{
	if(le <= l&&r<=ri){
		add[rt] += num;
		sum[rt] += (LL)num*(r-l+1);
		return;
	}
	pushdown(rt, r-l+1);
	int m = (l+r)>>1;
	if(le <=m) update(le, ri, num, LC);
	if(ri > m) update(le, ri, num, RC);
	pushup(rt);
}
LL query(int le, int ri, int l, int r, int rt)
{
	if(le <= l&&r<=ri){
		return sum[rt];
	}
	pushdown(rt, r-l+1);
	LL res = 0;
	LL m = (l+r)>>1;
	if(le <= m) res += query(le, ri, LC);
	if(ri > m) res += query(le, ri, RC);
	return res;
}
int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	creat(1, n, 1);
	char s[2];
	int a, b, c;
	while(m --){
		scanf("%s", s);
		if(s[0] == 'Q'){
			scanf("%d%d", &a, &b);
			printf("%I64d\n", query(a, b, 1, n, 1));
		}
		else{
			scanf("%d%d%d", &a, &b, &c);
			update(a, b, c, 1, n, 1);
		}
	}
	return 0;
}