zoukankan      html  css  js  c++  java
  • 【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
    ", x.first);
    	dfs(x.second, x.first);
    	
    	return 0;
    }
    
  • 相关阅读:
    file类和io流
    数组元素的填充与替换、排序和复制
    foreach遍历数组、数组的转置与方阵的迹
    Java小故事(一)
    java杨辉三角和空心菱形(二维数组篇)
    JAVA修饰符、关键字和继承(一)
    JAVA面向对象和类
    JAVA小程序-----买衣服
    JAVA流程控制
    Java包、类、数据类型、表达式和标识符
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P3506.html
Copyright © 2011-2022 走看看