线段树求调
查看原帖
线段树求调
439319
朦胧细雨楼主2021/7/24 10:08
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long

using namespace std;
const int N=4567898;
ll a[N],ans[N],tag[N];
ll k,n,m;

ll ltree(ll root);
ll rtree(ll root);
void push_up(ll root);
void push_down(ll root,ll left_,ll right_);
void build(ll root,ll left_,ll right_);
void add(ll left_,ll right_,ll root,ll k);
ll query(ll qul,ll qur,ll left_,ll right_,ll root); 
void work(ll addl,ll addr,ll left_,ll right_,ll root,ll k);
int main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	build(1,1,n);
	ll flag,l,r;
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&flag,&l,&r);
		switch(flag)
		{
			case 1:
			{
				scanf("%lld",&k);
				work(l,r,1,n,1,k);
				break;
			}
			case 2:
			{
				printf("%lld\n",query(l,r,1,n,1));
				break;
			}
		}
	}
	return 0;
}
void work(ll addl,ll addr,ll left_,ll right_,ll root,ll k)//区间修改操作
{
	if(addl<=left_&&addr>=right_)//目标区间完全覆盖x的控制区间 
	{
		tag[root]+=k;//懒标记+
		ans[root]+=k*(right_-left_+1);//区间和+ 
		return ;
	}
	push_down(root,left_,right_);//懒标记下放 
	ll mid=(left_+right_)/2;
	if(addl<=mid)//左子树含有目标区间 
		work(addl,addr,left_,mid,ltree(root),k);
	if(addr>mid)//右子树含有目标区间 
		work(addl,addr,mid+1,right_,rtree(root),k);
	push_up(root);//更新父节点区间和 
}

void build(ll root,ll left_,ll right_)//建树 
{
	tag[root]=0;
	if(left_==right_)
	{
		ans[root]=a[left_];//把值赋给区间和
		return ;
	}
	ll mid=(left_+right_)/2;//把区间分成两半
	build(ltree(root),left_,mid);
	build(rtree(root),mid+1,right_);
	push_up(root);//区间和数组初始化
	return ;
}
ll ltree(ll root)
{
	return root<<1;
}
ll rtree(ll root)
{
	return root<<1|1;
}
void push_up(ll root)//区间和向上传递
{
	ans[root]=ans[ltree(root)]+ans[rtree(root)];
	//父节点区间和等于左右区间和
	return; 
}
void push_down(ll root,ll left_,ll right_)//懒标记下放
{
	ll mid=(left_+right_)/2;
	add(left_,mid,ltree(root),tag[root]);//左子树数据修改
	add(mid+1,right_,rtree(root),tag[root]);//右子树数据修改
	tag[root]=0;//下放之后父节点懒标记清零
	return;
}
void add(ll left_,ll right_,ll root,ll k)
{
	tag[root]+=k;
	ans[root]+=k*(right_-left_+1);
	return;
}

ll query(ll qul,ll qur,ll left_,ll right_,ll root)
{//区间查询
	if(qul<=left_&&qur>=right_)//要查询的区间已经完全覆盖x控制区间 
		return ans[root];//直接返回x区间和
		
	ll s=0;//x控制范围内查询的结果 
	ll mid=(left_+right_)/2;
	push_down(root,left_,right_);//父节点懒标记下放
	if(qul<=mid)//左子树包含目标区间 
		s+=query(qul,qur,left_,mid,ltree(root));
	if(qur>=mid)//右子树包含目标区间
		s+=query(qul,qur,mid+1,right_,rtree(root));
	return s;
	
}

2021/7/24 10:08
加载中...