洛谷题面
题目大意
给你一个长度为 \(n\) 的序列 \(a_1,a_2,\cdots,a_n\),你需要把这 \(n\) 个元素分成三类:\(1,2,3\):
-
所有的最长上升子序列都不包含这个元素。
-
有但非所有的最长上升子序列包含这个元素。
-
所有的最长上升子序列都包含这个元素。
题目分析
令 \(f_i\) 表示 \(\{a_1,a_2,\cdots,a_i\}\) 的 \(\rm LIS\) 长度,\(g_i\) 表示 \(\{a_i,a_{i+1},\cdots,a_n\}\) 的 \(\rm LIS\) 长度,\(len\) 表示 \(\{a_1,a_2,\cdots,a_n\}\) 的 \(\rm LIS\) 长度。
对于 \(a_i\),若 \(f_i+g_i\neq len+1\),说明 \(a_i\) 这个点不在整个序列所有的 \(\rm LIS\) 方案里。那么 \(ans_i\gets 1\)。
若 \(f_i+g_i=len+1\),判断是否存在 \(f_i=f_j\) 且 \(g_i=g_j(i\neq j)\),则 \(a_i\) 一定属于第二种情况:有但非所有的最长上升子序列包含这个元素。因为其他元素和 \(a_i\) 某种意义上来说等价,都在其 \(\rm LIS\) 中起到同样的作用。
其他情况为最后一种情况。
\(f_i,g_i\) 可以用二分、线段树和树状数组在 \(\mathcal{O(n\log n)}\) 的时间内求得,记录是否出现重复可以用桶或 \(map\)。树状数组码量小,完爆线段树;树状数组容易理解,完爆二分。故此处选择树状数组。
代码
//2022/2/28
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include //need "INT_MAX","INT_MIN"
#include //need "memset"
#include
#include
#include