询问区间是否同色

来源:互联网 发布:广州用友java面试题 编辑:程序博客网 时间:2024/05/22 01:57
下面再看一个例子:有一条直线,每次把其中一段染成某种颜色,要求输出最终的染色
情况。
首先,可以把所有操作所涉及到的坐标离散化,从而可以用整数区间来表示直线上的线
段。然后,由于现在的问题不涉及区间的查询,只涉及区间的修改,我们不需要考虑“如何
合并两条线段的信息”这一问题,而只需考虑“如何在树上作标记以快速维护每个位置的颜
色”。不难发现,这个题目中,每个节点不需要记录前面意义上的“值”,而只需要记录前面
所说的“标记”。我们定义,一个节点上如果作了标记,就说明它所表示的区间里只有同一种
颜色,而这种颜色是由标记所表示的;如果没有作上标记,就说明需要看它的儿子节点,才
能确定它的颜色。
对于一开始完全没有染色的情况,直接把整个区间拆成O(log n)个被操作区间,然后分
别做上标记即可。但是如果遇到这样的情况,如节点[0,3]已经被标记了,但是我们这次修改
了[3,5],那么[0,3]的标记就不再有效,但是如果直接删除的话,那么[0,2]这个范围内的颜色
又记错了。这就需要我们再次使用“标记向下传”的办法,这次的传的方法比较简单,直接把
标记覆盖传给两个儿子节点,然后清空父亲节点的标记即可。回到刚才的第一句话,“对于
一开始完全没有染色的情况”,事实上甚至我们都不需要完全的初始化,只需要把根节点做
上一个“初始颜色”的标记,就行了。
在本题中加入随时询问某个位置的颜色,不需要对树进行任何更改即可完成。但是如果
加入了随时询问某一段是否同色,标记就不能这样随便传了:我们需要在一个节点所代表的
一段内是同色的时候,确保它作了标记。 这样,在每次修改过程结束后,我们还需要再检查 :
是不是这个节点其实可以打上标记?伪代码如下所示:
function change(v, l, r, color) // 把[l,r]范围内修改成color
if [l,r]和[v.l,v.r]没有交集
退出
end if
if l = v.l AND r = v.r
v.mark <- color
// 直接作上标记
退出
end if
if NOT v.mark = 未标记
v.lch.mark <- v.mark
v.rch.mark <- v.mark
v.mark <- 未标记
// 标记往下传
end if
change(v.lch,l,r,color)
change(v.rch,l,r,color)
if v.lch.mark = v.rch.mark AND NOT v.lch.mark = 未标记
v.mark <- v.lch.mark
// 更新v的标记状态
end if
end function
从这个例子可以看出来, “一个区间的颜色”这个性质, 既符合“相邻区间的信息能合并”,
又符合“标记可以向下传”。因此,没有绝对的“值”与“标记”的区分。所有的东西都是存在节
点里的信息,通过不同的方式得到维护。前面的例子把两者分开,只是着重强调这两个性质
分别的意义而已。
原创粉丝点击