CSP-S 2024 第八次
忘记写了,补一下
A
依次加入每个 \(a_i\),拿个大根堆维护当前以 \(i\) 结尾的和最大子段,和超过 \(s\) 了就弹堆顶直到和不超过 \(s\)。
……但是这样是错的,考虑加入一个负的 \(a_i\) 后,取堆中最小的几个数使得它们的和大于 \(0\),
则删掉这些数中的最大值后剩下的数也不会被取,也就是说要删掉这些数只需要删一次,把它们拿出来加在一起塞回去即可。
\(s\) 是负数的话删掉所有大于等于 \(s\) 的 \(a_i\) 即可。不过好像出现了一些语文事故,先不管了。
B
倍增预处理出 \(f_i\) 表示 \(i\) 上方第一个大于 \(a_i\) 的点,
询问 \(u,v,c\) 时,先倍增找到 \(u\) 上方第一个大于 \(c\) 的点 \(x\),然后就要求跳(\(x\gets f_x\))几次能跳出 \(v\),在 \(f\) 上倍增即可。
C
最大值最小,先二分最大值 \(K\)。
设 \(f_{u,x,y}\) 表示是否存在走完 \(u\) 子树,\(u\) 到第一个叶子的距离为 \(x\),最后一个叶子到 \(u\) 的距离为 \(y\) 的方案,
可以发现 \(x\le x',y\le y',f_{u,x,y}=1\) 时我们就不关心 \(f_{u,x',y'}\) 了,所以在我们关心的状态中 \(y\) 随 \(x\) 的增大而减小,
而且我们关心的 \(f_{u,x,y}\) 只有 \(O(s_u)\) 个(\(s_u\) 是 \(u\) 的叶子个数),因为 \(x,y\) 都只有这么多种。
考虑转移,钦定先走左子树时,对于左子树 \(l\) 中每个我们关心的状态 \(f_{l,x_1,y_1}\),
其能与右子树 \(r\) 中的 \(f_{r,x_2,y_2}\) 合并成 \(f_{u,x_1,y_2}\) 当且仅当 \(y_1+v_l+v_r+x_2\le K\),
而 \(y_2\) 肯定越小越好,所以肯定取满足条件的最大的 \(x_2\) 进行转移,双指针维护。
钦定先走右子树同理,最后只留下我们关心的状态就行。
D
【模板】最小斯坦纳树
设 \(f_{u,S}\) 表示以 \(u\) 为根的树覆盖 \(S\) 中的点的最小代价,考虑转移:
- 不改变根,可以合并已有的两棵树,即 \(f_{u,S}+f_{u,T}\to f_{u,S\cup T}\)。
- 改变根,可以在根上连接一条边,即 \(f_{u,S}+e(u,v)\to f_{v,S}\),其中 \(e(u,v)\) 是 \(u,v\) 之间的边权。
第一种转移直接枚举子集做,第二种转移类似 Dijkstra 地做即可。