[BZOJ4553][Tjoi2016&Heoi2016]序列(CDQ 分治优化 DP)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=4553

Solution

下面设三个值:
a i :原序列 i 位置的值。
a m i n i i 位置可能被变换成的最小数值。
a m a x i i 位置可能被变换成的最大数值。
而一个合法的子序列必须满足,对于相邻的两个位置 j , i ( j < i )
(1)即使 i 位置被变换成最小值也必须要满足单调不降的性质。
即:

a j a m i n i

(2)即使 j 位置被变换成最大值也必须要满足单调不降的性质。
即:
a m a x j a i

所以就有一个 dp 模型了!
f [ i ] 表示以 i 为结尾的最长子序列。
转移显然:
f [ i ] = 1 + max j < i , a j a m i n i , a m a x j a i f [ j ]

会发现这特别像 BZOJ 2253 纸箱堆叠(二维上升子序列)。
用二维线段树 / CDQ 分治优化,复杂度 O ( n log 2 n )

Code

发现 BZOJ 的空间限制不让二维线段树通过

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read() {
    int res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    return bo ? ~res + 1 : res;
}
const int N = 1e5 + 5;
int n, m, a[N], _min[N], _max[N], T[N], ans;
struct cyx {
    int _min, x, _max, id, res;
} q[N];
inline bool comp1(const cyx &a, const cyx &b) {
    return a.x < b.x || (a.x == b.x && a._max < b._max);
}
inline bool comp2(const cyx &a, const cyx &b) {
    return a._min < b._min || (a._min == b._min && a.x < b.x);
}
inline bool comp3(const cyx &a, const cyx &b) {
    return a.id < b.id;
}
void clean(int x) {
    for (; x <= 100000; x += x & -x)
        T[x] = 0;
}
void change(int x, int v) {
    for (; x <= 100000; x += x & -x)
        T[x] = max(T[x], v);
}
int ask(int x) {
    int res = 0;
    for (; x; x -= x & -x)
        res = max(res, T[x]);
    return res;
}
void zzqsolve(int l, int r) {
    if (l == r) return (void) (ans = max(ans, q[l].res));
    int i, p = l, mid = l + r >> 1;
    zzqsolve(l, mid);
    sort(q + l, q + mid + 1, comp1);
    sort(q + mid + 1, q + r + 1, comp2);
    For (i, mid + 1, r) {
        while (p <= mid && q[p].x <= q[i]._min)
            change(q[p]._max, q[p].res), p++;
        q[i].res = max(q[i].res, ask(q[i].x) + 1);
    }
    For (i, l, mid) clean(q[i]._max);
    sort(q + mid + 1, q + r + 1, comp3);
    zzqsolve(mid + 1, r);
}
int main() {
    int i, x, y;
    n = read(); m = read();
    For (i, 1, n) a[i] = _min[i] = _max[i] = read();
    while (m--) {
        x = read(); y = read();
        _min[x] = min(_min[x], y);
        _max[x] = max(_max[x], y);
    }
    For (i, 1, n) q[i] = (cyx) {_min[i], a[i], _max[i], i, 1};
    zzqsolve(1, n);
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81368986