线段树(四)——杨子曰算法

线段树(四)——杨子曰算法

传送门:线段树(三)
传送门:线段树集合


给一个长度为n(n<=200000)的序列,再给出m个操作,对于每个操作,先给出一个k,如果k=1,则输入x,y,输出区间[x,y]的和,如果k=2,则输入x,y,z,把区间[x,y]的每个元素加上z


欧,现在是线段树模板题的最后一个大BOSS了,也就是更新的是区间,询问的也是区间,看上去很恶心,现在解决它!(我们把add(lazy)和sum记在一个struct,看得清晰)


首先,他询问的是区间和,So,最开始肯定要build,不多说:

void build(int l,int r,int nod){
	tree[nod].add = 0;
	if (l==r){
		tree[nod].sum=a[l];
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,nod*2);
	build(mid+1,r,nod*2+1);
	tree[nod].sum=tree[nod*2].sum+tree[nod*2+1].sum;
}

再看update,这肯定得用lazy优化,就是区间吻合就完事,但更新sum的时候一定要注意区间吻合时,这个区间里的每一个元素可都得加上v,So,tree[nod].sum+=(r-l+1)*v
来看update:

void update(int l,int r,int ll,int rr,int v,int nod){
	if (l==ll &&r==rr){
		tree[nod].sum+=(r-l+1)*v;
		tree[nod].add+=v;
		return;
	}
	pushdown(nod, l, r);
	int mid=(l+r)/2;
	if (rr<=mid) update(l,mid,ll,rr,v,nod*2);
	else if (ll>=mid+1) update(mid+1,r,ll,rr,v,nod*2+1); 
	else {
		update(l,mid,ll,mid,v,nod*2);
		update(mid+1,r,mid+1,rr,v,nod*2+1);
	}
	pushup(nod);
}

这里有一个小问题pushdown怎么写,机智的大佬一定会写了,但我还要说一下,这个add是指对这个区间中的每个数都要加上它,那在计算左右儿子的sum的时候,要乘上儿子区间的对应元素个数(这也就是为什么pushdown要传l和r)

void pushdown(int nod, int l, int r) {
	int mid = (l+r)/2;
	tree[nod*2].sum+=(mid-l+1)*tree[nod].add;
	tree[nod*2+1].sum+=(r-mid)*tree[nod].add;
	tree[nod*2].add+=tree[nod].add;
	tree[nod*2+1].add+=tree[nod].add;
	tree[nod].add=0;
}

还有一个小问题,pushup怎么写?sum一定要pushup上去,那add呢?Of couse NOT!首先add本身记录的就是它儿子的变化量,再有,当你pushup的时候,你的add可是0诶,那你pushup什么鬼呢?

void pushup(int nod) {
	tree[nod].sum = tree[nod*2].sum + tree[nod*2+1].sum;
}

这样弄完了以后solve就简单了,更原来完全一样:

int solve(int l,int r,int ll,int rr,int nod){
	if (l==ll &&r==rr){
		return tree[nod].sum;
	}
	pushdown(nod, l, r);
	int mid=(l+r)/2;
	if (rr<=mid) return solve(l,mid,ll,rr,nod*2);
	else if(ll>=mid+1) return solve(mid+1,r,ll,rr,nod*2+1);
	else return solve(l,mid,ll,mid,nod*2)+solve(mid+1,r,mid+1,rr,nod*2+1);
}

OK!完事


啰嗦一下:
如果到目前为止,你对线段树一点问题都没有的话,Congratulations!——你终于略懂了线段树的皮毛,当然线段树的用处肯定不只是求求min,求求max,求求sum,之前也曰了线段树可以解决所有区间问题,对应的,线段树里记录的区间信息是不一样的

看道题:
给一个长度为n(n<=200000)的序列,再给出m个操作,对于每个操作,先给出一个k,如果k=1,则输入x,y,输出区间[x,y]中能被7整除的数的个数,如果k=2,则输入x,y,z,把区间[x,y]的每个元素加上z

好吧,最近写线段树写烦了,我也不知道什么时候再出线段树(五),等那时候再来给大家曰这道题吧!
OK,88
传送门:线段树(五)
于TJQ高层小区

未经作者允许,严禁转载:https://blog.csdn.net/henryyang2018/article/details/80014786

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值