扫描线类线段树正确性分析
对于线段树分析。
\(\mathcal{Goal: }\) 我们希望使用线段树维护区间大于0的数的个数,支持区间加/减。
\(\mathcal{Main\ \ Idea :}\) 方法:通过打加法 tag,直接维护答案。
由于扫描线的性质,区间减法相当于撤销上一次区间加,所以 tag 始终非负。
至于维护的值,我们只需要保证每次修改的节点到根路径上的点的答案都是正确的即可。
所以现在我们到一个结束节点 s,如果有 s 标记 \(\mathrm{tag}\not = {0}\) 那么 s 的答案值一定是 \(r-l+1\)。
否则 我们从儿子更新,s 的两个儿子一定是正确的(这个可以使用类似数学归纳法的证明)。
注意为什么有的时候我们不从儿子更新,因为有的时候儿子并没有被修改算过答案。
而此时如果 \(\mathrm{tag}=0\) 那么这个点答案是 0也显然;否则 \(\mathrm{tag} \not = 0\)是 \(r-l+1\) 也是正确的。
\(\mathcal{Conclusion}\)
大体做法如上了,说一下我认为值得注意的。
注意我们在维护这个区间加减,全局非0个数的时候是用到了扫描线的性质的,也就是撤销性质,即任意时刻 \(\mathrm{tag}\geq 0\),这个是异常重要的。
我并不会没有这个性质的区间该怎么维护。
同时也注意,我们只是保证了每次修改区间对应的节点 s,到根这条路径上点的正确性。
我认为这个看起来并不起眼的线段树在扫描线中并不是一个可以忽略的东西,更应该是最重要的东西,因为这个线段树现在看来是完全依靠扫描线性质的,把他们割裂开可是万万不得的。
如果有大佬能看到我的这篇博客,而且对我的观点,做法有不认可的地方,也欢迎在评论区提出。
\(\mathrm{done.}\)
update
还没有结束。。。。
扫描线其实远远不用这么麻烦的线段树。这个线段树用途感觉十分小,而且严格弱于接下来的这种方法。
不必考虑所谓的撤销操作。
有这样一个比撤销操作更加不严格的性质(要求)——任意时刻每个位置 >=0。
这样你其实可以只维护最小值,和最小值个数即可。
由于不会出负数,最小值肯定就是0,有贡献的;或>0,没有贡献的。
really done?