NOI2022模拟测试赛(二十二)

link

通道

自己对于二分图构造一个类 prufer 序列。

一个映射方式是合法的,只需要:

  • 一棵生成树能构造出一个 prufer 序列。
  • 能从一个 prufer 序列逆推回整棵树的形态,即过程中不会出现 “找不到” 或者 “找到多个合法解” 的情况。

敢造就敢有!

排列

转化后题意:

给定三个长度同为 \(n\) 的序列 \(V,A,B\),保证 \(V_i>0\)

求选出一个区间 \([l,r]\),最大化 \(\left(\sum_{i=l}^rV_i\right)+\min_{i=l}^r(A_i)+\min_{i=l}^r(B_i)\)

\(n\leq 10^6\)

题解:

用数据结构容易做到 \(O(n\log n)\),略去。此处讲线性做法:

看到区间 min,考虑建笛卡尔树,比如我们先对 \(A\) 序列建笛卡尔树。

笛卡尔树上一个点代表一段区间 \([L,R]\),且该区间内的任意子区间 \([l,r]\)\(A_{\min}\) 都相同,此时我们只需要考虑 \([L,R]\) 的所有子区间 \([l,r]\)\(\left(\sum_{i=l}^rV_i\right)+\min_{i=l}^r B_i\) 的最大值即可。

一个很重要的观察是:若 \(L<l\land r<R\),则 \([l,r]\) 必为 \(B\) 序列笛卡尔树的一个区间。

因为若不是,那么我们可以往两边扩使得 \(B_{\min}\) 不变且 \(\left(\sum_{i=l}^rV_i\right)\) 变大,直到 \([l,r]\)\(B\) 序列笛卡尔树上的一个区间或者 \(l=L\)\(r=R\) 为止。

所以我们先用 \(B\) 序列笛卡尔树上的所有区间更新一遍答案。这样 \(A\) 树上我们只需要考虑 \(l=L\)\(r=R\) 的情况即可。

两种情况是类似的,不妨考虑 \(l=L\),即区间为前缀的情况。

暴力的做法是用单调栈维护出 \([L,R]\)\(B\) 上前缀最小值的位置,假设它们分别为 \(p_1=L,\cdots,p_k\),那么显然 \(r\) 只可能在 \(p_2-1,\cdots,p_k-1\) 上取到(为了方便 \(l=L,r=R\) 的情况我们单独考虑)。

对于非暴力的方法,我们考虑合并两棵子树的单调栈。设左右儿子的 \(B\) 前缀最小值的单调栈分别为 \(BL,BR\)

显然合并这两个栈是均摊 \(O(1)\) 的。但关键是怎么更新答案。

实际上我们只需要对于单调栈上的每一个点 \(p_i\) 求出 \(s_{p_{i+1}-1}+B_{p_{i}}\) 的最大值即可。

左右儿子合并时可能会把 \(BR\) 的一段头给弹掉,为了快速得到剩下一段后缀的 \(s_{p_{i}-1}+B_{p_{i-1}}\) 最大值,我们还需要另外一个单调栈来维护 \(s_{p_{i}-1}+B_{p_{i-1}}\) 的后缀最大值。

记左右儿子维护这玩意后缀最大值对应的单调栈分别为 \(ML,MR\),那么我们合并两个儿子的整个算法流程如下:

  1. 合并 \(BL,BR\),过程中会弹掉 \(BR\) 左边的一段,此时对应弹掉 \(MR\) 中属于这一段的部分,并做更新。
  2. 合并 \(ML,MR\),过程中会弹掉 \(ML\) 右边的一段。

然后你发现我们有可能会对一个单调栈左右都弹,此时需要用一个链表来维护。

总时间复杂度 \(O(n)\)

posted @ 2022-10-31 08:15  ez_lcw  阅读(43)  评论(0)    收藏  举报