2023.8.10 线段树算法

T1 [HEOI2016/TJOI2016] 排序

luogu link

观察到只有一次询问 可能会有什么隐情
我们先考虑这样一件事 就是对一个 \(01\) 序列进行升序/降序排序
那么实际就是一个区间查和+区间赋值的操作

那么我们就可以考虑二分答案 然后把所有 \(\le mid\) 的数都赋成 \(0\) 其余赋 \(1\)
那么如果查询到的答案是 \(0\) 就代表这个位置的数 \(\le mid\)
否则代表这个位置的数 \(> mid\)


T2 窗口的星星

luogu link

考虑枚举窗口的位置不是很好做 我们考虑算每个星星的贡献
那么对于一个星星 它对应的一个贡献区间一定是一个宽为 \(W\) 高为 \(H\) 的矩形

那么问题就转化为了求平面内矩形相交的最大值
一个扫描线就做完了


T3 楼房重建

luogu link

首先第一步我们把坐标转化成斜率 这样我们能看到这一栋楼房 当且仅当它的斜率是它一段前缀的最大值

然后有修改操作 考虑到左右子区间似乎可以以某种方式转移出这个区间 所以考虑使用线段树

那么我们设 \(tr_i\) 表示这一段区间所对应的能看到的楼房数量

显然每次 \(pushup\) 那实际就是左半边的全部+右半边的后面一段
其实想到二分 但是发现我们没有维护这个上升序列具体每个位置的值

这时就有一个很神奇的做法 就是我们用 \(logn\) 来递归查这个信息
\(calc(k, h)\) 表示对于第 \(k\) 个节点 从高度 \(h\) 开始最长上升序列的长度
那么我们分情况讨论:

  • 左儿子没有高于 \(h\) 的 那就是 \(calc(k, h) = calc(rs, h)\)

  • 左儿子有高于 \(h\) 的 那就是左儿子的后一段+右儿子的全部
    那就是 \(calc(k, h) = tr_k - (tr_{ls} - calc(ls, h))\)

然后我们递归下去即可 这样一次 \(pushup\) 复杂度就是 \(O(logn)\) 总复杂度 \(O(nlog^2n)\)


T4 [BJOI2019] 删数

luogu link

我们首先考虑不带修怎么做

posted @ 2023-08-10 10:15  Steven24  阅读(12)  评论(0)    收藏  举报