P12547 [UOI 2025] Simple Subsequence 题解

介绍一种比较糖的维护方式。

首先区间可以从左到右贪心匹配,保证前缀和 \(\ge 0\) 即可。最终折线有一个最大值 \(mx\),和最终值 \(now\)。那么我们删去最后的 \(mx - now\)\(-1\) 即可。化一下式子,答案就是 \(2c_1 - mx\),其中 \(c_1\) 是区间中 \(1\) 的数量。

现在就是要维护区间匹配过程中的 \(mx\) 即可。即画一条从原点开始的折线,如果碰到 \(x\) 轴就不减了,整个过程的最大值。下面是我在模拟赛时想到的做法:

建线段树,每个线段树上维护节点代表区间的 \(mx\),左右边到最低点的距离 \(L,R\),还有不考虑和 \(0\)\(\max\) 时,折线的最大值 \(mx2\)

合并左右儿子的时候,\(L,R,mx2\) 均可以直接计算。对于 \(mx\),有 \(mx = \max(mx_{ls},mx_{rs},R_{ls} + mx2_{rs})\)

对于右儿子的过程,第一次碰到 \(x\) 轴前,\(mx2\) 是正确的,后面 \(mx\) 是正确的,其他时候答案一定更小。所以信息就维护对了。

inline void PushUp(node &i,node ls,node rs){
  i.c1=ls.c1+rs.c1;
  i.R=ls.R+std::max(0,rs.R-ls.L);
  i.L=rs.L+std::max(0,ls.L-rs.R);
  i.mx1=std::max({ls.mx1,ls.L+rs.mx2,rs.mx1});
  i.mx2=std::max(ls.mx2,rs.mx2+ls.L-ls.R);
}
posted @ 2025-07-25 21:46  KIreteria  阅读(15)  评论(0)    收藏  举报