思路
Step1: 直接 DP
- 状态定义
f [ i ] [ j ] f[i][j] f[i][j] 为 a [ 1 ] → a [ i ] a[1] \rightarrow a[i] a[1]→a[i] 中取长度为 j j j 的严格上升子序列时最后一个数的最小值。
- 状态转移
分三种情况讨论:
- f [ i − 1 ] [ j − 1 ] < l f[i-1][j-1]<l f[i−1][j−1]<l: f [ i ] [ j ] = l f[i][j]=l f[i][j]=l;
- f [ i − 1 ] [ j − 1 ] ≥ r f[i-1][j-1] \ge r f[i−1][j−1]≥r:状态不合法,不用转移了;
- l ≤ f [ i − 1 ] [ j − 1 ] < r l \le f[i-1][j-1] < r l≤f[i−1][j−1]<r: f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + 1 f[i][j]=f[i-1][j-1]+1 f[i][j]=f[i−1][j−1]+1。
Step2: Splay 优化
- 对于第一种, f [ i − 1 ] [ j − 1 ] f[i-1][j-1] f[i−1][j−1] 没用,直接赋值即可;
- 对于第三种,比较麻烦,可以先把最靠 r r r 的 f f f 删除,再插入一个 l l l,就可以移动整个区间。
- 题目思维很巧妙,但代码比较难实现(
代码
常数比较大,卡了挺长时间常才 AC 的(
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
struct node {
int s[2], fa, v, tag;
} t[N];
#define ls t[id].s[0]
#define rs t[id].s[1]
inline void rotate(int id) {
int fa = t[id].fa, ffa = t[fa].fa;
node &pre = t[id], &f1 = t[fa], &f2 = t[ffa];
bool c = f1.s[1] == id, cc = c ^ 1, c1 = f2.s[1] == fa;
if (ffa) {
f2.s[c1] = id;
}
int &son = pre.s[cc];
pre.fa = ffa, f1.s[c] = son;
if (son) {
t[son].fa = fa;
}
son = fa, f1.fa = id;
}
inline void pushdown(int id) {
if (!t[id].tag) {
return ;
}
int &tt = t[id].tag;
if (ls) {
t[ls].v += tt, t[ls].tag += tt;
}
if (rs) {
t[rs].v += tt, t[rs].tag += tt;
}
tt = 0;
}
int root;
void splay(int id, int f) {
stack<int> S;
S.push(id);
for (int i = id; t[i].fa; i = t[i].fa) {
S.push(t[i].fa);
}
while (S.size()) {
pushdown(S.top()), S.pop();
}
while (t[id].fa != f) {
int fa = t[id].fa, ffa = t[fa].fa;
if (ffa != f) {
rotate((t[fa].s[0] == id) == (t[ffa].s[0] == fa) ? fa : id);
}
rotate(id);
}
if (!f) {
root = id;
}
}
int find(int x) {
int id = root, res = 0;
while (id) {
pushdown(id);
if (t[id].v < x) {
res = id, id = rs;
} else {
id = ls;
}
}
return res;
}
inline int Nxt(int id) {
splay(id, 0), id = rs;
while (ls) {
id = ls;
}
return id;
}
inline int Pre(int id) {
splay(id, 0), id = ls;
while (rs) {
id = rs;
}
return id;
}
inline void del(int id) {
int pre = Pre(id), nxt = Nxt(id);
splay(pre, 0), splay(nxt, pre);
t[nxt].s[0] = t[id].fa = 0;
}
int k;
void ins(int x) {
int id = root, fa = 0;
while (id) {
pushdown(id);
fa = id, id = t[id].v > x ? ls : rs;
}
id = ++k;
if (fa) {
bool tt = t[fa].v <= x;
t[fa].s[tt] = id;
}
t[id].fa = fa, t[id].v = x;
splay(id, 0);
}
int main() {
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
ins(-1e9 - 10), ins(1e9 + 10);
int n;
cin >> n;
int res = n;
while (n--) {
int l, r;
cin >> l >> r;
int u = find(l), v = find(r), nxt = Nxt(v);
if (u ^ v) {
splay(u, 0), splay(nxt, u);
node &nxtt = t[t[nxt].s[0]];
++nxtt.v, ++nxtt.tag;
}
if (nxt != 2) {
del(nxt), --res;
}
ins(l);
}
cout << res << '\n';
return 0;
}