给你一个序列,然后每个位置有可以选的数的范围。
然后要你找到对于所有可能的序列它严格上升子序列的最大长度。
很明显的 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; }