我们回忆一下用朴素的dp的解法,对于一个数a[i],我们寻找a[1~i - 1]中小于a[i]的数的最长的子序列长度更新.这里,树状数组优化同样利用了这个思路.
我们假设为以值i(注意不是下标)结尾的最长上升子序列的长度,并且用树状数组维护f[x]值.由于值域很大,所以我们要先对值域进行离散化.接着,我们从前向后遍历数组a,找到小于a[i]的最大的x对应的f[x]值,并用f[x] + 1更新f[a[i]].
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, f[N], a[N], b[N], nn;
int find(int x) {
return lower_bound(b + 1, b + 1 + nn, x) - b + 1;
}
int ask(int x) {
int res = 0;
for (;x; x -= (x & -x))
res = max(res, f[x]);
return res;
}
void modify(int x, int k) {
for (; x <= N - 10; x += x & -x)
f[x] = max(k, f[x]);
}
signed main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(b + 1, b + 1 + n);
nn = unique(b + 1, b + 1 + n) - b - 1;
int maxv = 0;
for (int i = 1; i <= n; ++i) {
int q = ask(find(a[i]) - 1) + 1;
modify(find(a[i]), q);
maxv = max(maxv, q);
}
printf("%d\n", maxv);
}
对于这道题的数据,显然需要一个O(n^2)复杂度以下的方法,我们提供一个O(nlogn)的树状数组的做法.
对于题目的样例:
A: 3 2 1 4 5
B: 1 2 3 4 5
我们不妨重新标号
A: a b c d e
B: c b a d e
假设a < b < c < d < e,那么A序列就是一个完全的上升子序列,A与B的公共子序列一定是A的子序列,而最长的公共子序列一定是B的最长上升子序列,我们上面已经介绍如何用树状数组优化最长上升子序列问题了,这里就不再赘述.
代码如下:
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <map>
#include <unordered_map>
#include <vector>
#include <stack>
#include <time.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define PII pair<int, int>
#define PDI pair<double, int>
#define int long long
#define ll long long
#define ull unsigned long long
#define eps 1e-6
#define MOD 1000000007
#define debug(a) cout << #a << "=" << a << endl;
#define all(x) (x).begin(), (x).end()
#define mem(x, y) memset((x), (y), sizeof(x))
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 1e5 + 10;
int a[N], n, f[N];
map<int, int> mp;
void modify(int x, int k) {
for (; x <= n; x += x & -x)
f[x] = max(f[x], k);
}
int ask(int x) {
int ans = 0;
for (; x; x -= x & -x)
ans = max(ans, f[x]);
return ans;
}
signed main() {
#ifdef LOCAL
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
IOS;
cin >> n;
int tot = 0;
for (int i = 1, x; i <= n; ++i) {
cin >> x;
mp[x] = ++tot;
}
for (int i = 1; i <= n; ++i) {
cin >> a[i];
a[i] = mp[a[i]];
}
int maxv = 0;
for (int i = 1; i <= n; ++i) {
int q = ask(a[i] - 1) + 1;
modify(a[i], q);
maxv = max(maxv, q);
}
cout << maxv << "\n";
}