【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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/121001639
今日推荐