线段树(下)(填坑)

(上篇好像是好久以前的事了/捂脸)

       嗯。。下篇。。主要谈线段树的优化。。

      1.位运算(想必大家都会)  

           在向下递归时 p*2改成p<<1

                                  p*2+1改成p<<1|1

        解释:

             p<<=i相当于p*2^i

             p<<1 后 是偶数,在二进制下 末尾为0  |1 后 相当于 +1

        (这都不是重点,下面重点开始)

    2.延迟标记

          由例题引入:

                给定一个包含n个数的序列,初值全为0,现对这个序列有两种操作:

               操作1:将第k1 个数 到 第k2 个数加1;

               操作2:查询 从第k1个数到第k2个数得最大值。(k1<=k2<=n)

               所有的数都 <=100000

         题面很简洁。。但是实现就不一定了。我们所知线段树支持单点修改,但本题要求区间修改,怎么办。最初始的想法自然是把要修改的区间内每一个数都单点修改一次。。但复杂度就会变成O(n^2),这是我们不能承受的。思考:如果一个区间修改后我们之后都没有去查询,那么这次修改就是无用的,我们就从这里着手优化。

         我们给线段树上每个点一个标记,表示这个点已被修改,但其儿子还未修改,这个就叫延迟标记。这样就可以保证复杂度是O(nlogn),当然,常数更大了。。(线段树的常数反正是没救了)证明略

         贴代码:(我才不会说这段代码都没编译过

void change(int l,int r,int k)
{
	if(y<l||x>r) return;
	if(x<=l&&y>=r)
	{
		tree[k].maxx++;
		tree[k].lazy++;
		return;
	}
	int tz=tree[k].lazy,mid=(l+r)/2;
	tree[k*2].maxx+=tz;
	tree[k*2+1].maxx+=tz;
	tree[k*2].lazy+=tz;
	tree[k*2+1].lazy+=tz;
	tree[k].lazy=0;
	change(l,mid,k*2);
	change(mid+1,r,k*2+1);
	tree[k].maxx=max(tree[k*2].maxx,tree[k*2+1].maxx);
	return;
}

int ask(int l,int r,int k)
{
	if(y<l||x>r) return -1;
	if(x<=l&&y>=r)
	 return tree[k].maxx;
	int tz=tree[k].lazy,mid=(l+r)/2;
	tree[k*2].lazy+=tz;
	tree[k*2+1].lazy+=tz;
	tree[k*2].maxx+=tz;
	tree[k*2+1].maxx+=tz;
	tree[k].lazy=0;
	return max(ask(l,mid,k*2),ask(mid+1,r,k*2+1));
}

        注:建树过程没区别,标记的要如何灵活运用还是要自己靠刷题感觉
-------------------------------------------------------------------------坑总算是填完了---------------------------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值