单侧递归线段树专题
单侧递归线段树专题
Problem A. P4198 楼房重建
题意转化为 \(\tan\) 值的前缀最大值个数。线段树节点上维护区间前缀最大值个数 \(cnt\) 和区间最大值 \(mx\)。
考虑如何合并区间。设左子结点最大值为 \(k\),我们需要知道右子节点 \(>k\) 的前缀最大值个数。
设计一个函数 \(Ask(p,k)\) 表示 \(p\) 这个节点 \(>k\) 的前缀最大值个数。
若 \(ls.mx>k\),那么返回 \(p.cnt-ls.cnt+Ask(ls,k)\);否则,左子结点全军覆没,返回 \(Ask(rs,k)\)。
复杂度 \(O(n\log^2 n)\)。
记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
Problem B. AT_jsc2019_final_h Distinct Integers
设 \(pre_i\) 为 \(i\) 前面第一个与 \(a_i\) 相同的位置。一个 \([l,r]\) 合法, 当且仅当 \(\forall i\in [l,r],pre_i<l\)。
对于一个 \(r\),其合法的 \(l\) 是一个以 \(r\) 为右端点的区间。那么最小的左端点 \(L=\max_{1\le i\le r} pre_i+1\)。
维护区间前缀最大值之和即可。修改时只会影响 \(O(1)\) 个 \(pre_i\)。复杂度 \(O(n\log^2 n)\)。
Submission #66666904 - 第一回日本最強プログラマー学生選手権決勝 (atcoder.jp)
Problem C. CF1340F Nastya and CBS
将括号能匹配的都匹配掉。若出现 \((]\) 这种东西或有剩下的未匹配左/右括号就不合法。
线段树维护区间不匹配括号。精确匹配很难做,所以考虑哈希。
设 \(cl,cr\) 为节点未匹配右/左括号个数,\(vl,vr\) 为未匹配左/右括号的哈希值,以及 \(tag\) 为区间内有没有出现 \((]\)。
合并区间时,若子节点有 \(tag\) 标记,则直接返回;否则,假设 \(ls.cr>rs.cl\),那么需要求 \(rs\) 的前 \(k\) 个未匹配 \()\) 的哈希值。
设 \(Askl(p,k)\) 为 \(p\) 节点中前 \(k\) 个未匹配 \()\) 的哈希值。
若 \(ls.cl\ge k\),那么返回 \(Askl(ls,k)\);否则,返回 \(ls.vl+Askl(rs,k-ls.cl+ls.cr)-p.tmp\),其中 \(p.tmp\) 为 \(rs\) 的未匹配 \()\) 被 $ls $ 匹配掉的哈希值,预处理即可。
询问时,把区间内的 \(O(\log n)\) 个节点拿出来,一个个合并即可。
需要考虑哈希的高位、低位在哪边。复杂度 \(O(n\log^2 n)\)。
Submission #323970460 - Codeforces
Problem D. P9130 [USACO23FEB] Hungry Cow P
将草料看作 \((\),每一天上都有一个 \()\),维护被匹配掉的 \()\) 的权值和即可。
可以离散化,也可以动态开点线段树。复杂度 \(O(q\log^2 q)\) 或 \(O(q\log^2 V)\)。
记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
Problem E. P6781 [Ynoi2008] rupq
扫码卡常题,大粪。
\({\rm NAND}\) 没有结合律,不能直接维护区间 \({\rm NAND}\)。但是可以维护每一位 \(0/1\) 经过区间后会变成什么,可以位运算 \(O(1)\) 合并区间。
信息不能差分,只能合并,不能像上面那样维护了。
设 \(Askl(p,k)\) 为除去前 \(k\) 个的右括号后右括号的信息。若 \(ls.cl<k\),那么返回 \(Askl(rs,k-ls.cl+ls.cr)\);否则,返回 \(Askl(ls,k)+p.rv\),其中 \(p.rv\) 为右子节点被左子结点匹配完后剩下的信息。
因为有 3 操作,所以需要上平衡树。由于要保证树高时刻是 \(O(\log n)\) 的,所以用 FHQ-Treap。
\(mid\) 上有一个括号就很烦人,我们可以先合并 \([l,mid-1]\) 和 \(mid\),然后合并 \([l,mid],[mid+1,r]\)。贼屎。
还要卡常,能改非递归的尽量都改,但还是只有 76 pts,卡不动了。

浙公网安备 33010602011771号