CF809D

传送门

平衡树优化神题,完全想不到平衡树能这么用!

一看这题散发着一股 DP 的清香。

dp[i][j] 表示前 i 个数且第 i 个数为 j 的最长上升子序列长度。但是转移方程不好优化,状态表示可以滚动数组压掉一维。

反方向考虑 DP:dp[i][j] 表示前 i 个数最长上升子序列长度为 j,最后一个元素的最小值。同样滚动数组压掉一维。

dp[j]=min(dp[j],li),当 dp[j1]<li

dp[j]=min(dp[j],dp[j1]+1),当 dp[j1][li,ri)

dp[j]=dp[j],当 dp[j1]>ri

一个一个枚举太慢了!我们可以用平衡树维护所有 dp[j]。而且我们惊喜地发现 dp[] 存在单调性!dp[j]<dp[j+1],所以我们按照编号排序和按照值排序是一样的。

考虑每一个转移方程的影响,我们从整体来观察,而不是注意每一个 dp[j] 是否要转移。

第一个转移方程,在扫完 dp[1]dp[n] 之后,发现其实 dp[j]<ldp 不会变化,而只有 dp[j1]<l,dp[j]>l 的交界点才会发生变化。

(一开始就小于 l,与 lmin 当然不会变化。交界点更新完之后,更新的值至少是 l,也不会发生连锁反应,即不会交界点更新之后,更新的数又用第一条转移方程更新后面的。)

于是我们直接在平衡树上插入 li。(注意不是把小于 li 的最大数的后继变成 li,因为我们还需要用这个后继更新其他的 dp 值

第二个转移方程:相当于把所有 dp[j][li,ri) 的都加一,然后 dp[j+1]dp[j]

这第二个转移方程,会把 ri 且最小的 dp 值挤掉,替换成 <ri 且最大的 dp 值加一。所以我们直接删掉 ri 且最小的 dp 值就行。同时上面插入了一个 li,第二个转移方程都是 >li 的,刚好满足 dp[j+1]dp[j] 的需求。

总结一下:

  1. 把所有 [li,ri) 的都加一。

  2. 插入 li,注意这里顺序不能搞反,不然这个 li 会算进 [li,ri) 的里面。

    而且我们发现,本来应该删除 li 的最小值,再插入 li 的(变成 li),但是因为 [li,ri) 的都加一了,所以不用再删除 li 的最小值。

  3. 删除 ri 的最小值。

最后的答案就是平衡树的大小。

看到这么多的区间操作,当然是用可爱的 FHQ_Treap 啦!

区间加一就用懒标记的方法。

posted @   FLY_lai  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示