POJ 3468 A Simple Problem with Intergers (线段树区间更新模板题)

题意:

给出 N 个数 ,Q 个查询 ,区间更新,区间查询

数据范围:

1 < = N , Q < = 1 0 5 1<=N,Q<=10^5 1<=N,Q<=105 − 1 e 9 < = A i < = 1 e 9 -1e^9<=Ai<=1e^9 1e9<=Ai<=1e9

对 lazy 标志的理解::
  • 在update 的时候,当要更新的区间[A,B] 完全包含了 segment 的左右的端点时,不用接着再往下更新它的子节点的信息,因为如果再接着更新下去,设 lazy 数组就没有意义了,就相当于单点更新整段 [A,B] 一样。
  • 而拿到此次 lazy 标志的点,它的 sum 已经更新了, lazy 的作用是延迟了对子节点 sum 的更新,就好像大哥说:“小弟们,上头下来的钱我先给你们保管了。而当外界的人想要来询问小弟身价时,因为必要经过大哥点来找到小弟,这时大哥才把小弟们应有的钱 ( lazy 信息) pushdown下去。”
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ls x<<1
#define rs x<<1|1
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll a[N];
struct tnode{
	ll l,r,sum,lazy;
}t[N<<2]; //节点开至少 4 倍空间
void pushup(int x)
{
	t[x].sum=t[ls].sum+t[rs].sum;
}
void pushdown(int x)
{
	int mid=(t[x].l+t[x].r)>>1;
	if(t[x].lazy)//有标记就下传 
	{
		t[ls].lazy+=t[x].lazy;
		t[rs].lazy+=t[x].lazy;
		t[ls].sum+=(mid-t[x].l+1)*t[x].lazy;
		t[rs].sum+=(t[x].r-mid)*t[x].lazy; 
		t[x].lazy=0;
	}
}
void build(int l,int r,int x)
{
	t[x].l=l, t[x].r=r, t[x].lazy=0; //可以在建树时给 lazy 赋值,我觉得这样更结构化 
	if(l==r)
	{
		t[x].sum=a[l];  // l == r 叶子节点
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,ls);
	build(mid+1,r,rs);
	pushup(x);  //建完两个子节点后,要更新父节点的值,这对父节点的 sum 有影响
}
void update(int A,int B,int val,int x)
{
	if(A<= t[x].l && t[x].r<=B)
	{
		t[x].sum+=(t[x].r-t[x].l+1)*val;
		t[x].lazy+=val;
		return;
	}
	//没有完全覆盖,就去更新[A,B]和两个子节点有交集的部分
	pushdown(x); 
	int mid=(t[x].l+t[x].r)>>1;
	if(A<=mid)
		update(A,B,val,ls);
	if(mid<B)
		update(A,B,val,rs);
	pushup(x);  //两子节点的sum值变了,父节点的sum值也要变
}
ll query(int A,int B,int x)
{
	if(A<= t[x].l && t[x].r<=B) //t[x] 的整段贡献给 ans
		return t[x].sum;
	pushdown(x);   //询问的点在 x 的子节点,也是要同步看是否lazy标记,因为可能要查询的节点的sum的更新信息被上一个节点延迟了。
	ll ans=0, mid=(t[x].l+t[x].r)>>1;
	if(A<=mid)
		ans+=query(A,B,ls);
	if(mid<B)
		ans+=query(A,B,rs);
	return ans;
}
int main()
{
	ll n,q,u,v,c;
	char ch;
	cin>>n>>q;
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	build(1,n,1);
	while(q--)
	{
		getchar();
		scanf("%c %lld %lld",&ch,&u,&v);
		if(ch=='Q')
			printf("%lld\n",query(u,v,1));
		else
		{
			scanf("%lld",&c);
			update(u,v,c,1);
		}	
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值