洛谷P3372解题报告

题目描述如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190723202836726.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2R3aDEwNDE1MTgyODI=,size_16,color_FFFFFF,t_70)
由于是一道模板题就直接给注释详细的代码。
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
long long int sum=0LL;
struct node
{
  	ll l;
	ll r;
	ll f;/* 
	f为懒惰标记,因为比较懒,如果暂时不用该节点的子节点的话,就不改变他子节点的值 ;
	但是如果以后要用的话就需要改变了,而懒惰标记就是用来检查此次是否需要改变子节点的值。 
	*/ 
	ll v; 
}tree[500005];
void build(ll l,ll r,ll k)
{//建立线段树 
	tree[k].l=l;//该区间左端点为l; 
	tree[k].r=r;//该区间右端点为r; 
	if(l==r)
	{
	cin>>tree[k].v;//如若分到一个点如区间[3,3],输入,并返回。 
	return;	
	}
	int mid=(l+r)/2;//二分法生成树 
	build(l,mid,k*2);
	build(mid+1,r,k*2+1); 
	tree[k].v=tree[k*2].v+tree[k*2+1].v;//由于是返回,所以先更改的是子节点的值。 
										//父节点等于两个子节点(区间)值的和 
}
void passdown(ll k)
{
	tree[k*2].f+=tree[k].f;//将父亲的懒惰标记给左儿子 
	tree[k*2+1].f+=tree[k].f;//将父亲的懒惰标记给右儿子
	tree[k*2].v+=(tree[k*2].r-tree[k*2].l+1)*tree[k].f;//左儿子的值等于原值+左儿子集合元素个数乘父亲的懒惰标记。 
	tree[k*2+1].v+=(tree[k*2+1].r-tree[k*2+1].l+1)*tree[k].f;//右儿子同理。 
	tree[k].f=0;//取消父亲的懒惰标记。 
}  
void add(ll p,ll q,ll k,ll w)
{
	if(tree[k].l>=p && tree[k].r<=q)
	{
		tree[k].f+=w;//如果符合小于所求区间标记懒惰标记。 
		tree[k].v+=(tree[k].r-tree[k].l+1)*w;//因为是给区间内所有物品加值,所以是加上w*n 
		return;//必须返回 
	}
	if(tree[k].f)//如果已经找到寻找的区间之一 
	passdown(k);//由于之前只把懒惰标记传递到了要用点便停止,他的子节点的值并未改变所以要下传懒惰标记。 
	ll mid=(tree[k].l+tree[k].r)/2;//二分搜索 
	if(p<=mid)add(p,q,k*2,w);
	if (q>mid) add(p,q,k*2+1,w);
	tree[k].v=tree[k*2].v+tree[k*2+1].v;//返回时改变父节点的值。 
}
void sear(ll p,ll q,ll k)
{
	if(tree[k].l>=p && tree[k].r<=q)
	{
		sum+=tree[k].v;
		return;
	}
	if(tree[k].f)
	passdown(k);//由于之前只把懒惰标记传递到了要用点便停止,他的子节点的值并未改变所以要下传懒惰标记。
	long long int mid=(tree[k].l+tree[k].r)/2;
	if(p<=mid) sear(p,q,k*2);
	if(q>mid) sear(p,q,k*2+1);	
}

int main()
{ 
	ll n,m,x,flag,s,e,ad;
	cin>>n>>m;//输入 
	build(1,n,1);
	for(int i=1;i<=m;i++)
	{
		cin>>flag>>s>>e;
		if(flag==2)
		{
			sum=0;
			sear(s,e,1);
			cout<<sum<<endl; 
		} 
		else
		{
			cin>>ad; 
			add(s,e,1,ad);
		}
	}
	
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值