(Relax 线段树1.1)POJ 3468 A Simple Problem with Integers(线段树子区间更新的维护:集中更新和动态统计子序列中的数据)

本文介绍了一种使用线段树进行区间更新和查询的方法,通过懒惰标记优化操作效率,适用于解决大规模数据集上的区间修改与求和问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


/*
 * POJ_3468.cpp
 *
 *  Created on: 2013年11月25日
 *      Author: Administrator
 */

#include <iostream>
#include <cstdio>

#define maxn 100010
#define Fup(i, s, t) for (int i = s; i <= t; i ++)
#define Fdn(i, s, t) for (int i = s; i >= t; i --)

using namespace std;

struct node {//线段树
	long long mark;//节点i的懒惰标记为tree[i].mark
	long long sum;//节点i的数和为tree[i].sum
} tree[maxn * 4];

int x[maxn];//初始值序列
int n;//数字个数
int m;//操作次数

void update(int l, int r, int i) {//标记法维护线段树(根为i,对应区间[l,r])
	if (!tree[i].mark)
		return;
	int mid = (l + r) / 2;
	tree[i + i].sum += tree[i].mark * (long long) (mid - l + 1);
	tree[i + i + 1].sum += tree[i].mark * (long long) (r - mid);
	tree[i + i].mark += tree[i].mark;
	tree[i + i + 1].mark += tree[i].mark;
	tree[i].mark = 0;
}

long long query(int tl, int tr, int l, int r, int i) {//计算线段树的数字和(根为i,对应区间[l,r]内子区间[tl,tr]的数字和)
	if (tl > r || tr < l)
		return 0;
	if (tl <= l && r <= tr)
		return tree[i].sum;
	update(l, r, i);
	int mid = (l + r) / 2;
	return query(tl, tr, l, mid, i + i) + query(tl, tr, mid + 1, r, i + i + 1);
}


//线段树中区间[l,r]的子区间[tl,tr]中的每个数+val
void add_value(int tl, int tr, int l, int r, int i, int val) {
	if (tl > r || tr < l)
		return;
	if (tl <= l && r <= tr) {
		tree[i].sum += val * (long long) (r - l + 1);
		tree[i].mark += val;
		return;
	}
	update(l, r, i);
	int mid = (l + r) / 2;
	add_value(tl, tr, l, mid, i + i, val);
	add_value(tl, tr, mid + 1, r, i + i + 1, val);
	tree[i].sum = tree[i + i].sum + tree[i + i + 1].sum;
}

//建立根为i,对应区间[1..n]的线段树
void build_tree(int l, int r, int i) {
	if (l == r) {
		tree[i].sum = x[l];
		return;
	}
	int mid = (l + r) / 2;
	build_tree(l, mid, i + i);
	build_tree(mid + 1, r, i + i + 1);
	tree[i].sum = tree[i + i].sum + tree[i + i + 1].sum;
}

void solve(){
	build_tree(1,n,1);//****别漏了,记得要先建线段数

	char ch;
	int i;
//	scanf("\n");
	for(i = 1 ; i <= m ; ++i){
		int l,r,v;
		scanf(" %c",&ch);
		if(ch == 'Q'){
			scanf("%d%d",&l,&r);

			long long ans = query(l,r,1,n,1);
			printf("%lld\n",ans);
//			cout<<ans<<endl;
		}else if(ch == 'C'){
			scanf("%d%d%d",&l,&r,&v);

			add_value(l,r,1,n,1,v);
		}
	}
}

int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		int i;
		for(i = 1 ; i <= n ; ++i){
			scanf("%d",&x[i]);
		}

		solve();
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气的东哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值