这题可以把问题转化为,对于一个位置,限制的位置必然是,递增时候,小于他本身,或者递减时候,大于他本身的位置,然后在这个区间中,寻找最大(小)值的位置,这样利用线段树维护即可,对于一个限制位置,可以先把数字离散化掉,然后用权值做节点很容易就处理出来了,然后第二个问题就是普通的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; }
时间: 2024-09-29 03:04:25