开始觉得是个什么两次遍历法,后来发现是RMQ问题,可以选择线段树,树状数组,ST表三种
再看数据范围:(N <= 10^5)
线段树/树状数组:(O(nlogn))
ST表:(O(n))
#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 100010;
int a[N];
int maxv[N][20], minv[N][20];
int n;
vector<int> res;
void init(){
int k = log(n) / log(2);
for(int i = 1; i <= n; i ++) maxv[i][0] = a[i];
for(int i = 1; i <= n; i ++) minv[i][0] = a[i];
for(int j = 1; j <= k; j ++)
for(int i = 1; i + (1 << j) - 1 <= n; i ++){
maxv[i][j] = max(maxv[i][j - 1], maxv[i + (1 << j - 1)][j - 1]);
minv[i][j] = min(minv[i][j - 1], minv[i + (1 << j - 1)][j - 1]);
}
}
int query_max(int l, int r){
if(r < l) return -1;
int k = log(r - l + 1) / log(2);
return max(maxv[l][k], maxv[r - (1 << k) + 1][k]);
}
int query_min(int l, int r){
if(r < l) return 0x3f3f3f3f;
int k = log(r - l + 1) / log(2);
return min(minv[l][k], minv[r - (1 << k) + 1][k]);
}
int main(){
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
init();
for(int i = 1; i <= n; i ++){
int l = query_max(1, i - 1), r = query_min(i + 1, n);
// cout << l << ' ' << r << endl;
if(l < a[i] && r > a[i]) res.push_back(a[i]);
}
sort(res.begin(), res.end());
cout << res.size() << endl;
if(res.size()){
cout << res[0];
for(int i = 1; i < res.size(); i ++) cout << ' ' << res[i];
}else puts("");
return 0;
}
两次遍历法:(O(n))
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 100010;
int minv[N], maxv[N];
int n;
int a[N];
vector<int> res;
int main(){
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
maxv[1] = -1;
minv[n] = 0x3f3f3f3f;
for(int i = 2; i <= n; i ++) maxv[i] = max(maxv[i - 1], a[i - 1]);
for(int i = n - 1; i >= 1; i --) minv[i] = min(minv[i + 1], a[i + 1]);
for(int i = 1; i <= n; i ++)
if(maxv[i] < a[i] && minv[i] > a[i]) res.push_back(a[i]);
sort(res.begin(), res.end());
cout << res.size() << endl;
if(res.size()){
cout << res[0];
for(int i = 1; i < res.size(); i ++) cout << ' ' << res[i];
}else puts("");
return 0;
}