这题可以把问题转化为,对于一个位置,限制的位置必然是,递增时候,小于他本身,或者递减时候,大于他本身的位置,然后在这个区间中,寻找最大(小)值的位置,这样利用线段树维护即可,对于一个限制位置,可以先把数字离散化掉,然后用权值做节点很容易就处理出来了,然后第二个问题就是普通的rmq问题
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100005;
int n, a[N];
struct Hash {
int v, id;
void read(int i) {
this->id = i;
scanf("%d", &v);
}
} h[N];
bool cmp(Hash a, Hash b) {
return a.v < b.v;
}
#define lson(x) ((x<<1)+1)
#define rson(x) ((x<<1)+2)
struct Node {
int l, r, Min, Max;
} node[N * 4];
void pushup(int x) {
node[x].Min = min(node[lson(x)].Min, node[rson(x)].Min);
node[x].Max = max(node[lson(x)].Max, node[rson(x)].Max);
}
void build(int l, int r, int x = 0) {
node[x].l = l; node[x].r = r;
if (l == r) {
node[x].Min = n + 1;
node[x].Max = 0;
return;
}
int mid = (l + r) / 2;
build(l, mid, lson(x));
build(mid + 1, r, rson(x));
pushup(x);
}
void add(int v, int val, int x = 0) {
if (node[x].l == node[x].r) {
node[x].Max = node[x].Min = val;
return;
}
int mid = (node[x].l + node[x].r) / 2;
if (v <= mid) add(v, val, lson(x));
else add(v, val, rson(x));
pushup(x);
}
int find(int l, int r, int x = 0) {
if (node[x].l >= l && node[x].r <= r)
return node[x].Min;
int mid = (node[x].l + node[x].r) / 2;
int ans = n + 1;
if (l <= mid) ans = min(ans, find(l, r, lson(x)));
if (r > mid) ans = min(ans, find(l, r, rson(x)));
return ans;
}
int get(int l, int r, int bo, int x = 0) {
if (node[x].l >= l && node[x].r <= r) {
if (bo) return node[x].Max;
return node[x].Min;
}
int ans;
if (bo) ans = 0;
else ans = n + 1;
int mid = (node[x].l + node[x].r) / 2;
if (l <= mid) {
if (bo) ans = max(ans, get(l, r, bo, lson(x)));
else ans = min(ans, get(l, r, bo, lson(x)));
}
if (r > mid) {
if (bo) ans = max(ans, get(l, r, bo, rson(x)));
else ans = min(ans, get(l, r, bo, rson(x)));
}
return ans;
}
int v[N], post[N];
int ans[N], an;
int main() {
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; i++)
h[i].read(i);
sort(h + 1, h + n + 1, cmp);
for (int i = 1; i <= n; i++)
a[h[i].id] = i;
for (int i = 1; i <= n; i++)
post[a[i]] = i;
build(1, n);
add(a[n], n);
for (int i = n - 1; i >= 1; i--) {
if (a[i + 1] < a[i]) v[i] = find(a[i] + 1, n);
else v[i] = find(1, a[i] - 1);
add(a[i], i);
}
for (int i = 1; i <= n; i++)
add(i, a[i]);
int u = 1;
an = 0;
while (u < n) {
ans[an++] = u;
u = post[get(u, v[u] - 1, a[u + 1] > a[u])];
}
ans[an++] = u;
printf("%d\n", an);
for (int i = 0; i < an; i++)
printf("%d%c", ans[i], i == an - 1 ? '\n' : ' ');
}
return 0;
}