您的位置:首页 > 其它

谈区间合并线段树

2011-08-29 10:45 225 查看
对于以前做的区间合并线段树颇有微词,对于大神们使用三个数组来记录节点的情况很是不解。对于当前点,只需要能提供所需的w长度区间即可向下进行判断,左子树优先提供,左右子树合并提供,右子树最后提供,否则输出不可行。

故我认为只需要一个记录当前节点的情况的数组即可,不需要三个数组,故用一个数组实际编写了代码。后发现此法是不行的.... 首先判断左右子树能否提供的问题,lsum+rsum>=w则返回m-lsum+1,这样用三个数组很方便,若用一个数组会有很多bug,因为一个数组只是记录自己的情况:左右子树提供给自己的东西。而没有考虑区间的连续性。举例来说:1-10的线段树,左子树右子树分别提供4,但是5,6两点已经被占,这时要提供8长度的区间显然不可能,但是只用一个数组会出现可行的情况而且答案是2.为何要使用三个数组?因为我对这些数组各自的功能不是很清楚,现在来看,lsum与rsum有各自的用处。lsum,rsum各自记录当前点向左向右的连续区间各多长,也就是说这两个数组实际上起的作用就是用来判断区间连续与否。

void PushUp( int rt,int m )
{
lsum[rt]=lsum[rt<<1]; //当前lsum直接取左子树的lsum[]值
rsum[rt]=rsum[rt<<1|1]; //当前sum直接取右子树的rsum[]值
if( lsum[rt]==(m-(m>>1)) )lsum[rt]+=lsum[rt<<1|1];//若左子树是满的,则向右拓展 求和
if( rsum[rt]==m>>1 )rsum[rt]+=rsum[rt<<1];//若右子树是满的,则向左拓展 求和
msum[rt]=max( lsum[rt<<1|1]+rsum[rt<<1],max( msum[rt<<1],msum[rt<<1|1]) );
//当前msum的值为左右子树中空闲点,和 左子树的右边和右子树的左边的和中最大值
}

合并区间的重要操作就在于PushUp操作中,其他的地方lsum与rsum用法相同,共同更新,这也是我产生错觉的原因。看来对于理解这些算法真的很是重要啊~ 我果然还是太弱了!加油!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法