题解 SP2371 【LIS2 - Another Longest Increasing Subsequence Problem】
听说此题还没有题解,所以蒟蒻我来一发题解。
这道题是一道三维偏序(cdq分治。
cdq分治
需要注意的是,在递归处理
所以过程大概是这样的:
void cdq(int l, int r) {
if (l == r) return; //基本情况
int mid = (l + r) >> 1;
cdq(l, mid);
处理[l, mid]对[mid+1, r]的影响
cdq(mid + 1, r);
}
至于如何处理
//计算[l,mid]对(mid,r]的影响
for (int i = l; i <= r; ++i) id[i] = i;
sort(id + l, id + r + 1, cmpa); //排序
for (int i = l; i <= r; ++i)
if (id[i] <= mid) BIT.add(b[id[i]], dp[id[i]]);
else dp[id[i]] = max(dp[id[i]], BIT.query(b[id[i]] - 1) + 1);
for (int i = l; i <= r; ++i)
if (id[i] <= mid) BIT.clr(b[id[i]]); //清理BIT
有不懂的地方可以看下面的代码(含注释)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 200007;
int n, n_, ans, a[N], b[N], c[N], dp[N], id[N];
bool cmpa(int i, int j) {
return a[i] < a[j] || a[i] == a[j] && i > j; //避免x[i]=x[j]的影响,使得x[i]=x[j]的时候查询操作在前
}
struct BinaryIndexTree { //树状数组
int mx[N];
void add(int i, int x) {
for (; i <= n_; i += i & -i)
mx[i] = max(mx[i], x);
}
int query(int i) {
int res = 0;
for (; i >= 1; i -= i & -i)
res = max(res, mx[i]);
return res;
}
void clr(int i) {
for (; i <= n_; i += i & -i)
mx[i] = 0;
}
} BIT;
void cdq(int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
cdq(l, mid);
//计算[l,mid]对(mid,r]的影响
for (int i = l; i <= r; ++i) id[i] = i;
sort(id + l, id + r + 1, cmpa);
for (int i = l; i <= r; ++i)
if (id[i] <= mid) BIT.add(b[id[i]], dp[id[i]]);
else dp[id[i]] = max(dp[id[i]], BIT.query(b[id[i]] - 1) + 1);
for (int i = l; i <= r; ++i)
if (id[i] <= mid) BIT.clr(b[id[i]]);
cdq(mid + 1, r);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d%d", &a[i], &b[i]), dp[i] = 1, c[i] = b[i];
//离散化
sort(c + 1, c + n + 1);
n_ = unique(c + 1, c + n + 1) - c - 1;
for (int i = 1; i <= n; ++i) b[i] = lower_bound(c + 1, c + n_ + 1, b[i]) - c;
cdq(1, n);
for (int i = 1; i <= n; ++i) ans = max(ans, dp[i]);
printf("%d\n", ans);
return 0;
}