通道
自己对于二分图构造一个类 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\),那么我们合并两个儿子的整个算法流程如下:
- 合并 \(BL,BR\),过程中会弹掉 \(BR\) 左边的一段,此时对应弹掉 \(MR\) 中属于这一段的部分,并做更新。
- 合并 \(ML,MR\),过程中会弹掉 \(ML\) 右边的一段。
然后你发现我们有可能会对一个单调栈左右都弹,此时需要用一个链表来维护。
总时间复杂度 \(O(n)\)。
标签:二十二,弹掉,min,最大值,序列,NOI2022,模拟,区间,单调 From: https://www.cnblogs.com/ez-lcw/p/16843030.html