ZJOI2019 minmax 搜索

给定一棵有根树 (T),根节点深度为 (1),每个节点的深度为其父亲的深度 (+1),每个叶子节点的权值为其编号,现定义每个非叶节点的权值:

  • 对于深度为奇数的非叶节点,其权值为其子节点的权值最大值。
  • 对于深度为偶数的非叶节点,其权值为其子节点的权值最小值。

然后我们得到根节点的权值 (W)

对于一个叶子节点的集合 (S),我们现给集合 (S) 的点分配一个新权值 (w_i) 后,使得按照上述规则计算中 (W) 的权值改变,定义这个分配 (w_i) 的方案的权值为 (max_{iin S}|i-w_i|)(w(S)) 为所有方案中最小的权值。

设叶子节点数为 (m),对于所有的 (2^m-1) 个叶子节点集合,设 (f(k)) 为有多少个集合满足 (w(S)=k),给定 (L,R),求 (f(L)+f(L+1)+...+f(R))

答案对 (998244353) 取模。

( m Sol:)

嘴巴 AC 一下...代码枯了

观察到答案要么变大要么变小。

如果答案要变小,那么我们肯定是将集合内所有元素都减去 (k)

然后统计有多少个集合可以使得答案变化。

不难发现我们求的大概是 (sum f(x)[xle k]),设为 (g(k)),差分一下就可以得到答案了。

但是 (g(k)) 直接求不太好求,因为实际上我们可以求出来的是有多少个集合满足变小后合法,变大后合法,存在一些集合满足变大/变小都合法。

他们是要减去的。

事实上那些集合满足变大/变小均合法也很好算,Dp 的时候维护 (4) 个数组就可以了 (f_{u,0/1,0/1}) 表示变大的情况下大于/小于,变小的情况下大于/小于。

于是就得到了一个 (mathcal O((R-L)cdot n)) 的算法。

具体 check 大概是对于某个 (k),对于变小的情况,假设 (i-k<W),那么设为 (0),否则设为 (1),那么取 (min) 就是按位 (&),取 (max) 就是按位或,大于的情况同理。

进一步优化就考虑直接维护 (mathcal O(n)) 个数组,设 (f_{u,0/1,0/1,k}) 表示对于 (k),考虑到点 (u)((0/1, 0/1)) 情况下的答案。

不难发现转移其实是将数组对应部分乘起来并做加法的过程。

初始值也是插入在某个状态的一段区间内。

用线段树合并维护即可,要维护加法标记和乘法标记,复杂度 (mathcal O(nlog n)),空间复杂度 (mathcal O(nlog n)),会附带 (4) 的常数。

代码枯了。

原文地址:https://www.cnblogs.com/Soulist/p/13638263.html