模糊序列 / Hitchhiking in the Baltic States
题目链接:YBT2022寒假Day2 B / luogu CF809D
题目大意
给你一个序列,然后每个位置有可以选的数的范围。
然后要你找到对于所有可能的序列它严格上升子序列的最大长度。
思路
很明显的 DP。
考虑列方程,发现数的范围很大,考虑从答案序列长度下手,设 \(f_{i,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;
}