猫树

算法发明者:猫锟(巨佬),先贴上他本人的文章:猫树——by 猫锟

猫树的本质:预处理部分区间的答案,需要时直接合并。

那么可以对询问的序列造一个线段树,然后预处理线段树上每一个点所对应的区间的答案,需要时合并即可。

很经典的问题:区间最大子段和。

对于树上的每一个节点,我们维护这样几个元素(设这个节点管理的区间为 l l l~ r r r):

1、 s l sl sl,表示必须选 l l l位置上的数,能得到的最大子段和。
2、 s r sr sr,表示必须选 r r r位置上的数,能得到的最大子段和。
2.5 、那么实际上我们可以认为, s l sl sl s r sr sr分别表示从左边延伸出来的最大子段和右边延伸出来的最大子段和
3、 a n s ans ans,表示这一段区间内的最大子段和。
4、 s u m sum sum,表示这一段区间内所有数的和。

那么就得到了这样的转移过程:

sum=zuo->sum+you->sum;//sum的话直接加起来就好
sl=max(zuo->sl,zuo->sum+you->sl);//sl可以直接是左儿子的sl,或者是全选左儿子加上右儿子的sl
sr=max(you->sr,you->sum+zuo->sr);//sr类似
ans=max(zuo->ans,max(you->ans,zuo->sr+you->sl));//ans要么是左儿子的ans,要么是右儿子的ans,要么是左右儿子拼起来后中间的那一段

求解的代码是这样子的:

node *find(int x,int y)
{
	if(l==x&&r==y)return this;//如果和询问的区间一样,就返回自己
	int mid=l+r>>1;
	if(y<=mid)return zuo->find(x,y);//否则去左右找
	else if(x>=mid+1)return you->find(x,y);
	else//如果在中间,就分两半做
	{
		node *left=zuo->find(x,mid),*right=you->find(mid+1,y);//记录下左右儿子的答案
		node *re=new node();//对左右儿子的答案进行合并
		re->sum=left->sum+right->sum;
		re->sl=max(left->sl,left->sum+right->sl);
		re->sr=max(right->sr,right->sum+left->sr);
		re->ans=max(left->ans,max(right->ans,left->sr+right->sl));
		return re;
	}
}

模板题在此   完整代码

如果以后发现猫树的神奇应用一定会贴上来的。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值