题解:AT_arc159_d [ARC159D] LIS 2
HHH6666666666 · · 题解
提供一个避开分类讨论的小结论没什么用。
令
实际上可以强化成
证明显然:令
得证。
问题变成区间加一次函数和查询区间内单点最值。线段树维护即可。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 10;
const int LGN = 50;
int n;
struct Segment {
int ls, rs;
int max, maxb;
Segment() { maxb = -1e9; }
} a[MAXN * LGN];
int idx, root;
#define Max(x, y) x = max(x, y)
#define mid ((L + R) >> 1)
void maxit(int p, int b, int L, int R) {
if (!p) return;
a[p].maxb = max(a[p].maxb, b);
a[p].max = max({a[p].maxb + R, a[a[p].ls].max, a[a[p].rs].max});
return;
}
void pushdown(int p, int L, int R) {
if (!a[p].ls) a[p].ls = ++idx;
if (!a[p].rs) a[p].rs = ++idx;
maxit(a[p].ls, a[p].maxb, L, mid);
maxit(a[p].rs, a[p].maxb, mid + 1, R);
return;
}
void pushup(int p, int L, int R) {
a[p].max = max({a[p].maxb + R, a[a[p].ls].max, a[a[p].rs].max});
return;
}
void add(int &p, int l, int r, int b, int L = 1, int R = 1e9) {
if (!p) p = ++idx;
if (l <= L && R <= r) { maxit(p, b, L, R); return; }
pushdown(p, L, R);
if (l <= mid) add(a[p].ls, l, r, b, L, mid);
if (mid < r) add(a[p].rs, l, r, b, mid + 1, R);
pushup(p, L, R);
return;
}
int query(int p, int l, int r, int L = 1, int R = 1e9) {
if (!p || l > r) return 0;
if (l <= L && R <= r) return a[p].max;
pushdown(p, L, R);
int res = 0;
if (l <= mid) Max(res, query(a[p].ls, l, r, L, mid));
if (mid < r) Max(res, query(a[p].rs, l, r, mid + 1, R));
return res;
}
signed main() {
ios:: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
while (n--) {
int l, r; cin >> l >> r;
int t = query(root, 1, l - 1);
add(root, l, r, t + 1 - l);
}
cout << query(root, 1, 1e9) << endl;
return 0;
}