线段树算法

一维数组
1.建树

void build(int l,int r,int o)//l,r表示当前节点区间,rt表示当前节点编号
{
	if(l==r){//到叶节点,修改 
		cin>>a[o];
		return ;
	}
	int mid=(l+r)>>1;//根据条件判断往左子树调用还是往右 
	build(l,mid,o<<1);
	build(mid+1,r,o<<1|1);
	a[o]=a[o<<1]+a[o<<1|1];//子节点更新了,所以本节点也需要更新信息
 } 

2.修改
(一)点修改:

void update(int L,int C,int l,int r,int o){//l,r表示当前节点区间,o表示当前节点编号
	if(l==r){//到叶节点,修改 
		a[o]+=C;
		return;
	}
	int m=(l+r)>>1;
	//根据条件判断往左子树调用还是往右 
	if(L <= m) Update(L,C,l,m,o<<1);
	else       Update(L,C,m+1,r,o<<1|1);
	a[o]=a[o<<1]+a[o<<1|1];//子节点更新了,所以本节点也需要更新信息 
} 

(二)区间修改:

void Update(int L,int R,int C,int l,int r,int o){//L,R表示操作区间,l,r表示当前节点区间,o表示当前节点编号 
	if(L <= l && r <= R){//如果本区间完全在操作区间[L,R]以内 
		a[o]+=C*(r-l+1);//更新数字和,向上保持正确
		Add[o]+=C;//增加Add标记,表示本区间的Sum正确,子区间的Sum仍需要根据Add的值来调整
		return ; 
	}
	int m=(l+r)>>1;
	PushDown(o,m-l+1,r-m);//下推标记
	//这里判断左右子树跟[L,R]有无交集,有交集才递归 
	if(L <= m) update(L,R,C,l,m,o<<1);
	if(R >  m) update(L,R,C,m+1,r,o<<1|1); 
    a[o]=a[o<<1]+a[o<<1|1];//更新本节点信息 
} 

查询
询问A[L,R]的和
首先是下推标记的函数:

void PushDown(int rt,int ln,int rn){
	//ln,rn为左子树,右子树的数字数量。 
	if(Add[rt]){
		//下推标记 
		Add[rt<<1]+=Add[rt];
		Add[rt<<1|1]+=Add[rt];
		//修改子节点的Sum使之与对应的Add相对应 
		a[rt<<1]+=Add[rt]*ln;
		a[rt<<1|1]+=Add[rt]*rn;
		//清除本节点标记 
		Add[rt]=0;
	}
}

区间查询

int Query(int L,int R,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
	if(L <= l && r <= R){
		//在区间内,直接返回 
		return Sum[rt];
	}
	int m=(l+r)>>1;
	//下推标记,否则Sum可能不正确
	PushDown(rt,m-l+1,r-m); 
	
	//累计答案
	int ANS=0;
	if(L <= m) ANS+=Query(L,R,l,m,rt<<1);
	if(R >  m) ANS+=Query(L,R,m+1,r,rt<<1|1);
	return ANS;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值