染色问题题意概要
给定一个长度为n的数字序列,有m次对[Li,Ri]的涂色(或其他修改),求最后的序列
其实这种题最突出的特征是覆盖,即后面的操作会覆盖前面的操作,所以若一段区间被修改多次,取最后一次修改即可;
一:线段树做法
其实这种题一看,用线段树,再一看,还是线段树,耐着性子看最后一遍,仍是线段树。所以就开始码吧!
其实呢这题用普通线段树有一点麻烦了,因为这种题同一点标记只会有一个,要那区间l和r干啥嘞,zkw线段树那么好用,用zkw线段树可以优化时间,最后从上往下走(千万别告诉zkw我把他的线段树从上往下走了),一旦找到标记,看看这个区间的叶子节点数k,直接输出k个标记即可
二:并查集做法
这种题用线段树还是有一丢丢浪费,即便用zkw,O(nlogn)的复杂度还是在那里滴,有一个神奇的线性做法,其实感性地想一想(我已经分不清理性还是感性了) 若是从后往前时光把m个操作反过来,先操作m,m-1,……,1然后已经染色过的点就不操作了。
理想很远大,但操作就不简单了
操作不简单?
操作很简单
既然操作过这个区间就不必再操作了,那么为了达到线性时间,在下一次询问时就必须直接跳过其。
那么可不可以直接将区间左端点直接指向右端点呢?
当然不可以。举个小栗子:若先修改[3,5]再操作[1,6],那在最后输出路径的时候就会忽略[3,5]。
有一个解决方法,就是将该区间所有节点都指向右边的节点,并将区间左端点的左边的点飞跃整个区间,指向右端点的右边的点,这样在下一次访问到区间后就会直接飞过整个区间。
再举个栗子:当修改了[3,5]后
2->6->空白
3->4->5->颜色
再修改[1,6]后
1->2->6->颜色
3->4->5->颜色
我们十分惊奇的发现,前面拜访过的区间之后不会拜访了,所以无论有多少次修改,时间永远都是线性的(包括最后的输出),最后输出使用棒棒的路径压缩,又是线性的 \(^o^)/~ 庶民的胜利