7.5讲题
【PR 5】双向奔赴
记录 \(f_{S,i,j},g_S\) 分别表示当前即将或已经在强连通上的点为 \(S\),走到 \(i\),终点在 \(j\)(保证终点在环上)的答案,还要 \(S\) 是强连通的答案。转移的话先枚举 \(S\),然后枚举终点 \(j\),枚举在环上的点 \(s\in S\),和不在环上的 \(i\) 且 \((s,i)\) 有边,\(g_S \to f_{S,i,j}\)。\(f_{S,i,j} + a_{i,k} \to f_{S\cup i,k,j}(k\notin S,\exist (i,k))\)。转移到 \(g_S\):\(f_{S,i,j} + a_{i,j} \to g_{S \cup i}\)。复杂度 \(\Theta(2^n n^3)\)。
注意:从 \(g\) 转移到 \(f\) 时若起点 \(s\) 和终点 \(j\) 重合,那么要转移到 \(f_{S\cup i,i,j}\),防止走回头路。
AGC043D
无序归并的性质(对于任意长度):将每个序列划分为若干前缀最大值,把相邻两个不同前缀最大值中的所有数和小的那个前缀最大值看成一块,那么把这些有序块归并就说最后的结果。
长度为 \(3\) 的序列归并,一个序列为合法归并结果的充要条件
- 元素个数为 \(2\) 的块个数必须小于等于元素个数为 \(1\) 的块个数。
- 相邻两个前缀最大值下标相差不超过 \(3\)。
于是设 \(f_{i,j}\) 为放了前 \(i\) 个数形成若干整块,且元素个数为 \(1\) 的块减元素个数为 \(2\) 的块大小为 \(j(j\ge 0)\)。转移是简单的,有 \(2\binom{i+2}{2} f_{i,j} \to f_{i+3,j},(i+1)\cdot f_{i,j \to f_{i+2,j-1}},f_{i,j} \to f_{i+1,j+1}\)。复杂度 \(\Theta(n^2)\)。
注意 \(j\) 可能为负。
「JOI Open 2020」黑白点
注意到答案的上界是对于每个匹配,都会有左右两边点数的 \(\min\) 条线段与它相交,这是可以取到的,构造方法是选一个点为起点,每个点往后面第一个与它不同色的连边。那么就是要最大化每个匹配长度和,最后再除以 \(2\),设长度为 \(l\),贡献有 \(l-1\) 个。最大不好求,考虑最小,把每个白点对称到另一侧,那就是让 \(n-l-1\) 的和最大,也就是 \(n(n-1)\) 减去最小的 \(l\) 和。考虑一个点上重合的黑白点直接匹配最优,然后黑看成 \(1\),白看成 \(-1\),也就是要平均分配,可以往左右传值(\(a_i \leftarrow a_i - x,a_{i+1} \leftarrow a_{i+1}+x\)),让传值次数最小。经典的糖果传递。复杂度 \(\Theta(n\log n)\),在于排序。
[APIO2022] 游戏
考虑记录每个点能到的最前的点 \(suf_i\),和能到每个点最后面的点 \(pre_i\),当 \(pre_i \ge suf_i\) 时有环。
- 考虑 \(\Theta((n+m)k)\) 暴力,每次连边直接暴力 bfs 更新每个点,连 \(u \to v\) 时,会使 \(pre_v \leftarrow \max(pre_v, pre_u),suf_u \leftarrow \min(suf_u, suf_v)\)。
- 考虑什么时候更新时才会形成环,也就是当 \(u\) 的 \([pre_u,suf_u]\) 完全在 \([pre_v,suf_v]\) 的右侧才行,这启发我们并不需要记录具体的位置,只用搞清相对位置即可。由于是区间,考虑一个线段树的分治结构,把每段区间放到最浅的节点使得 \(pre_i \le mid < suf_i\),记录当前节点为 \(cur_i\)。连边 \(u\to v\) 时,考虑分情况更新。
- 若 \(cur_u=cur_v\),更新并不会使得它们的所在节点改变。
- 若 \(\operatorname{lca}(cur_u,cur_v) \neq cur_u \land \operatorname{lca}(cur_u,cur_v) \neq cur_v\),即它们在不同在子树中时
- 若 \(cur_u\) 在 \(cur_v\) 左边,无变化,退出。
- 若 \(cur_u\) 在 \(cur_v\) 右边,找到环。
- 若 \(cur_v\) 在 \(cur_u\) 左子树中,\(cur_u\) 会移动到 \(lson_u\),继续更新。
- 若 \(cur_v\) 在 \(cur_u\) 右子树中,无变化,退出。
- 若 \(cur_u\) 在 \(cur_v\) 左子树中,无变化,退出。
- 若 \(cur_u\) 在 \(cur_v\) 右子树中,\(cur_v\) 会移动到 \(rson_v\),继续更新。
- 每次加边 \((u,v)\) 时,若 \(u\) 被更新了,就重新更新所有 \(w \to u\) 的 \(w\)。若 \(v\) 被更新就重新更新所有 \(v \to w\) 的 \(v\) 。由于每个点只会被更新 \(\Theta(\log k)\) 次, 也会更新其他点 \(\Theta(\log k)\) 次,所以总复杂度是 \(\Theta((n + m)\log k)\)。
【UNR #6】稳健型选手
考虑单次询问,可以贪心,由于前 \(2\) 个最多选 \(1\) 个,前 \(4\) 个最多选 \(2\) 个 \(\cdots\) 所以可以直接用个堆维护,每次加入这个数,遇到 \(2i\) 这个位置加完后取走最小的那个数,剩下的就是答案。同理,假设区间长度为偶数(奇数最后一个一定会取),那么从后往前取 \(2i\) 个至少取 \(i\) 个,所以从后往前加入堆,每次 \(2i\) 的时候取最大那个就行。
考虑多次询问,可以考虑两个已经确定答案的区间如何合并,设 \(S,T\) 分别为两边取的,\(S',T'\) 为没取的,那么合并之后一定会从 \(S\) 中删掉 \(k\) 个数,从 \(T'\) 中取走 \(k\) 个数,且删掉最大的小于加入最小的,可以二分处理。既然可以合并,不妨考虑分治,每次处理所有 \([L,R]\) 跨过 \(mid\) 的询问。那么考虑从 \(mid\) 出发,先预处理右边的前缀 \(T'\) 和答案,用第一种贪心并且用主席树存下来,然后从 \(mid\) 扫到 \(l\),用第二种贪心。每次合并直接二分即可。
复杂度 \(\Theta((n+q)\log^2 n)\)。
[ZJOI2019] 语言
对于一个 \(u\) 的所有合法 \(v\) 的个数即为所有穿过 \(u\) 的路径并形成的虚树大小。考虑确定 \(k\) 个关键点 \(p_1,p_2,\cdots p_k\) 如何求出虚树大小。先将它们按 dfn 排序,答案为 \(\dfrac{1}{2} \sum\limits_{i=1}^k dis(p_i, p_{i \operatorname{mod} k+1})\)。于是考虑树上差分,每次遇到路径 \(s\) 或 \(t\) 时将 \((dfn_s,dfn_t)\) 位置激活,遇到 \(lca(s,t)\) 后将 \((dfn_s,dfn_t)\) 删除,可以线段树合并或启发式合并维护。线段树记录前驱、后缀即可,距离可以 \(\Theta(1)\) lca 算。
复杂度 \(\Theta((n+m)\log n)\)。

浙公网安备 33010602011771号