POJ 3468 :A Simple Problem with Integers——区间更新线段树经典题目

本文介绍了一种使用线段树和懒惰传播优化区间更新及查询的经典算法。通过具体实例演示了如何实现高效的区间加法更新与求和查询,特别适用于需要频繁进行区间操作的问题。

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

/*

经典区间成段更新题目。

题意:给出一个长度n的数字序列,已经m个操作,
Q操作给出l,r:访问区间[l,r]的数字和;
C操作给出l,r,x:将区间[l,r]内的所有数字都加上x。
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

*/

花了好些天研究ppt与别人的题解,不断的手动模拟才稍微理解lazy标记的熟络。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100005
#define LL __int64

struct node
{
	int l,r;
	LL lazy,sum;  //lazy为延迟标记
	int Len() { return r-l+1; }
	int Mid() { return (l+r)>>1; }
}tree[3*maxn];
int a[maxn];

void Lazy(int p)
{
	if(tree[p].lazy)
	{
		tree[p<<1].lazy+=tree[p].lazy;
		tree[p<<1|1].lazy+=tree[p].lazy;
		
		tree[p<<1].sum+=tree[p<<1].Len()*tree[p].lazy;
		tree[p<<1|1].sum+=tree[p<<1|1].Len()*tree[p].lazy;
		tree[p].lazy=0;
	}
}

void BuildTree(int p,int l,int r)
{
	tree[p].l=l,tree[p].r=r,tree[p].lazy=0;
	if(l==r)
	{
		tree[p].sum=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	BuildTree(p<<1,l,mid);
	BuildTree(p<<1|1,mid+1,r);
	tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}

void change(int p,int l,int r,int x)
{
	if(tree[p].l==l&&tree[p].r==r)
	{
		tree[p].lazy+=x;
		tree[p].sum+=x*tree[p].Len();
		return;
	}
	
	Lazy(p);  //标记下传
	int mid=tree[p].Mid();
	if(r<=mid)
		change(p<<1,l,r,x);
	else if(l>mid)
		change(p<<1|1,l,r,x);
	else
	{
		change(p<<1,l,mid,x);
		change(p<<1|1,mid+1,r,x);
	}
	tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}

LL query(int p,int l,int r)
{
	if(tree[p].l==l&&tree[p].r==r)
		return tree[p].sum;
	Lazy(p);
	int mid=tree[p].Mid();
	if(r<=mid)
		return query(p<<1,l,r);
	else if(l>mid)
		return query(p<<1|1,l,r);
	else
		return query(p<<1,l,mid)+query(p<<1|1,mid+1,r);
}

int main()
{
	int n,Q,l,r,x,i;
	char orde[3];
	scanf("%d%d",&n,&Q);
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	BuildTree(1,1,n);
	while(Q--)
	{
		scanf("%s%d%d",orde,&l,&r);
		if(l>r)
			swap(l,r);
		if(orde[0]=='C')
		{
			scanf("%d",&x);
			change(1,l,r,x);
		}
		else
			printf("%I64d\n",query(1,l,r));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值