【YBT2022寒假Day2 B】【luogu CF809D】模糊序列 / Hitchhiking in the Baltic States(平衡树优化DP)(fhq-Treap)

模糊序列 / Hitchhiking in the Baltic States

题目链接:YBT2022寒假Day2 B / luogu CF809D

题目大意

给你一个序列,然后每个位置有可以选的数的范围。
然后要你找到对于所有可能的序列它严格上升子序列的最大长度。

思路

很明显的 DP。
考虑列方程,发现数的范围很大,考虑从答案序列长度下手,设 fi,j 为前 i 个数答案串为 j 长度的最后一个最小是多少。

那么我们显然可以得出这个东西是严格递增的。
那我们考虑新一个数放进来会怎么样。

前面比 l 小的一段全部都会可以放一个 l,这个后面中比 r 小的一段全部都可以放比它大 1 的数。
然后前面那一段由于是递增只有最后一个会有效,所以我们可以相当于这样:
那这一段后面放一个 l,然后把中间的一段全部加一,然后把中间后面的一个删掉。

不难想到可以用 fhq-Treap 加速实现。

代码

#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; int n, l, r; struct fhq_Treap { int ls[1000001], rs[1000001], yj[1000001]; int val[1000001], tot, sz[1000001], root; int lyza[1000001]; int make_new(int va) { int now = ++tot; ls[now] = rs[now] = 0; yj[now] = rand(); val[now] = va; sz[now] = 1; return now; } void up(int now) { sz[now] = sz[ls[now]] + sz[rs[now]] + 1; } void downa(int x, int va) { val[x] += va; lyza[x] += va; } void down(int now) { if (lyza[now]) { if (ls[now]) downa(ls[now], lyza[now]); if (rs[now]) downa(rs[now], lyza[now]); lyza[now] = 0; } } pair <int, int> split_rnk(int now, int rnk) { if (!now) return make_pair(0, 0); if (!rnk) return make_pair(0, now); pair <int, int> re; down(now); if (sz[ls[now]] >= rnk) { re = split_rnk(ls[now], rnk); ls[now] = re.second; up(now); re.second = now; } else { re = split_rnk(rs[now], rnk - sz[ls[now]] - 1); rs[now] = re.first; up(now); re.first = now; } return re; } pair <int, int> split_val(int now, int va) { if (!now) return make_pair(0, 0); pair <int, int> re; down(now); if (va < val[now]) { re = split_val(ls[now], va); ls[now] = re.second; up(now); re.second = now; } else { re = split_val(rs[now], va); rs[now] = re.first; up(now); re.first = now; } return re; } int merge(int x, int y) { if (!x || !y) return x + y; if (x) down(x); if (y) down(y); if (yj[x] < yj[y]) { rs[x] = merge(rs[x], y); up(x); return x; } else { ls[y] = merge(x, ls[y]); up(y); return y; } } void insert(int x, int rnk) { int now = make_new(x); pair <int, int> y = split_rnk(root, rnk); root = merge(merge(y.first, now), y.second); } void build(int l, int r) { for (int i = l; i <= r; i++) insert((i == 0) ? 0 : 2e9, i); } void work(int l, int r) { pair <int, int> x = split_val(root, l - 1); pair <int, int> y = split_val(x.second, r - 1); downa(y.first, 1); pair <int, int> z = split_rnk(y.second, 1); y.second = z.second; int tmp = z.first; down(tmp); val[tmp] = l; root = merge(x.first, merge(tmp, merge(y.first, y.second))); } }T; int main() { // freopen("vague.in", "r", stdin); // freopen("vague.out", "w", stdout); srand(19491001); scanf("%d", &n); T.build(0, n); for (int i = 1; i <= n; i++) { scanf("%d %d", &l, &r); T.work(l, r); } printf("%d", T.sz[T.split_val(T.root, 2e9 - 1).first] - 1); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT2022Day2_B.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示