POJ A Simple Problem with Integers (线段树区间更新区间查询模板)

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


题意:N个数,Q个操作,操作有两种,‘Q a b ’是询问a~b这段数的和,‘C a b c’是把a~b这段数都加上c。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
struct node{
	int l, r, m;
	ll val, book;
};
const int maxn = 100100;
node T[maxn << 2];
int a[maxn];
void pushup(int rt)  {
	T[rt].val = T[rt << 1].val + T[rt << 1 | 1].val;
}
void pushdown(int rt) {
	if(T[rt].book) {  
        T[rt << 1].book += T[rt].book;  
        T[rt << 1 | 1].book += T[rt].book;  
        T[rt << 1].val += T[rt].book * (T[rt << 1].r - T[rt << 1].l + 1);  
        T[rt << 1 | 1].val += T[rt].book * (T[rt << 1 | 1].r - T[rt << 1 | 1].l + 1);  
        T[rt].book = 0;  
    }
}
void build(int begin, int end, int rt) {
	T[rt].l = begin;
	T[rt].r = end;
	T[rt].m = (T[rt].l + T[rt].r) >> 1;
	T[rt].book = 0;
	if(begin == end) {
		T[rt].val = a[begin];
		return ;
	}
	build(T[rt].l, T[rt].m, rt << 1);
	build(T[rt].m + 1, T[rt].r, rt << 1 | 1);
	pushup(rt);
}
void update(int L, int R, int num, int rt) {
	if(L <= T[rt].l && T[rt].r <= R) {
		T[rt].book += num;
		T[rt].val += (ll)num * (T[rt].r - T[rt].l + 1);
		return ;
	}
	pushdown(rt);
	if(L > T[rt].m) update(L, R, num, rt << 1 | 1);  
    else if(R <= T[rt].m) update(L, R, num, rt << 1);  
    else {  
        update(L, T[rt].m, num, rt << 1);  
        update(T[rt].m + 1, R, num, rt << 1 | 1);  
    }  
    pushup(rt);
}
ll query(int L, int R, int rt) {
	if(L <= T[rt].l && T[rt].r <= R) {
		return T[rt].val;
	}
	pushdown(rt);
	if(R <= T[rt].m) return query(L, R, rt << 1);
	else if(L > T[rt].m) return query(L, R, rt << 1 | 1);
	else return query(L, T[rt].m, rt << 1) + query(T[rt].m + 1, R, rt << 1 | 1);
}

int main() {
	int n, q;
	scanf("%d %d", &n, &q);
	for(int i = 1; i <= n; i++) scanf("%d", a + i);
	build(1, n, 1);
	getchar();
	char op;
	int x, y, z;
	while(q--) {
		scanf("%c", &op);
		if(op == 'Q') {
			scanf("%d %d", &x, &y);
			printf("%I64d\n", query(x, y, 1));
		}
		else {
			scanf("%d %d %d", &x, &y, &z);
			update(x, y, z, 1);
		}
		getchar();
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值