【luogu P3506】MOT-Monotonicity 2(线段树)
MOT-Monotonicity 2
题目链接:luogu P3506
题目大意
给你一个数组,以及 k 个大小关系,然后要你找到一个最长的子序列,使得它相邻的两个数依次满足 k 个大小关系(跑完 k 个就回到一开始继续)
思路
考虑 DP,但是普通的 DP 并不可以。
考虑用线段树优化。
其实就分成三个 DP,代表下一个符号是哪个,最后一个数是啥的最大长度。
然后至于方案你就记录一下到时跑回去即可。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n, k, a[500001], tmp[500001];
int pl[500001][3];
char c, s[500001];
struct XD_tree {
int a[500001 << 2], p[500001 << 2];
void up(int now) {
if (a[now << 1] > a[now << 1 | 1]) a[now] = a[now << 1], p[now] = p[now << 1];
else a[now] = a[now << 1 | 1], p[now] = p[now << 1 | 1];
}
void insert(int now, int l, int r, int pl, int va, int vp) {
if (l == r) {
if (va > a[now]) {
a[now] = va;
p[now] = vp;
}
return ;
}
int mid = (l + r) >> 1;
if (pl <= mid) insert(now << 1, l, mid, pl, va, vp);
else insert(now << 1 | 1, mid + 1, r, pl, va, vp);
up(now);
}
pair <int, int> query(int now, int l, int r, int L, int R) {
if (L > R) return make_pair(0, 0);
if (L <= l && r <= R) return make_pair(a[now], p[now]);
int mid = (l + r) >> 1, re = 0;
if (L > mid) return query(now << 1 | 1, mid + 1, r, L, R);
if (mid >= R) return query(now << 1, l, mid, L, R);
pair <int, int> x = query(now << 1, l, mid, L, R);
pair <int, int> y = query(now << 1 | 1, mid + 1, r, L, R);
if (x.first > y.first) return x;
else return y;
}
}T[3];
void csh() {//离散化
for (int i = 1; i <= n; i++) tmp[++tmp[0]] = a[i];
sort(tmp + 1, tmp + tmp[0] + 1);
tmp[0] = unique(tmp + 1, tmp + tmp[0] + 1) - tmp - 1;
for (int i = 1; i <= n; i++) a[i] = lower_bound(tmp + 1, tmp + tmp[0] + 1, a[i]) - tmp;
}
int get_op(int i) {
if (s[i] == '<') return 0;
if (s[i] == '=') return 1;
return 2;
}
void dfs(int now, int num) {//按着记录找回去
if (!num) return ;
dfs(pl[now][get_op((num - 2 + k) % k)], num - 1);
printf("%d ", tmp[a[now]]);//因为你离散化了,所以你要输出的是你找到的位置对于的数在离散化前的结果
}
int main() {
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
csh();
for (int i = 0; i < k; i++) {
c = getchar();
while (c != '=' && c != '<' && c != '>') c = getchar();
s[i] = c;
}
for (int i = 1; i <= n; i++) {
pair <int, int> x;
x = T[0].query(1, 1, n, 1, a[i] - 1);
pl[i][0] = x.second;
T[get_op(x.first % k)].insert(1, 1, n, a[i], x.first + 1, i);
x = T[1].query(1, 1, n, a[i], a[i]);
pl[i][1] = x.second;
T[get_op(x.first % k)].insert(1, 1, n, a[i], x.first + 1, i);
x = T[2].query(1, 1, n, a[i] + 1, n);
pl[i][2] = x.second;
T[get_op(x.first % k)].insert(1, 1, n, a[i], x.first + 1, i);
}
pair <int, int> x = max(T[0].query(1, 1, n, 1, n), max(T[1].query(1, 1, n, 1, n), T[2].query(1, 1, n, 1, n)));
printf("%d\n", x.first);
dfs(x.second, x.first);
return 0;
}