牛客小白月赛28 E-会当凌绝顶,一览众山小 线段树+二分暴力模拟

传送门:https://ac.nowcoder.com/acm/contest/16081/E

题意

  • 登山顺序不一定从左到右,是按照给出山峰的顺序
  • 找到左边第一个大于当前山峰的山峰的坐标,修改它
  • 如果右边没有大于当前山峰的,找到离当前山峰最近的最矮山峰,修改它

思路

首先顺序是按照给出的山峰顺序,并且x坐标过大,但是点数只有2e5,所以需要离散化。

对于一个点,需要找到左边和右边两个特殊要求的山峰,这个过程可以二分。 并且是区间查询,所以需要线段树维护,维护区间最大值和最小值即可。

  • 左边:假设当前是第i座山,映射过去的位置是pos(离散化),二分[1,pos]区间,找到最近的一个大于当前高度的山
  • 右边:同理。假设映射的位置是pos,先求出区间[pos+1,n]的最大值判断需不需要修改。若是需要,则二分[pos+1,n]区间,找到最近的一个最小值

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
##include "bits/stdc++.h"
using namespace std;

const int N = 2e5 + 10;

struct node {
int x, h;
}a[N];
int b[N], h[N], idx[N];

##define lc u << 1
##define rc u << 1 1
##define mid (t[u].l + t[u].r) / 2

struct Tree {
int l, r;
int mx, mn;
}t[N << 2];

inline void push_up(int u) {
t[u].mx = max(t[lc].mx, t[rc].mx);
t[u].mn = min(t[lc].mn, t[rc].mn);
}

void build(int u, int l, int r) {
t[u].l = l; t[u].r = r;
if(l == r) {
t[u].mx = t[u].mn = h[l];
return ;
}
int m = (l + r) / 2;
build(lc, l, m);
build(rc, m + 1, r);
push_up(u);
}

void modify(int u, int p, int v) {
if(t[u].l == t[u].r) {
t[u].mn = t[u].mx = v;
return ;
}
if(p <= mid) modify(lc, p, v);
else modify(rc, p, v);
push_up(u);
}

int query_max(int u, int ql, int qr) {
if(ql <= t[u].l && t[u].r <= qr) return t[u].mx;
int mx = -1e9 - 7;
if(ql <= mid) mx = max(mx, query_max(lc, ql, qr));
if(qr > mid) mx = max(mx, query_max(rc, ql, qr));
return mx;
}

int query_min(int u, int ql, int qr) {
if(ql <= t[u].l && t[u].r <= qr) return t[u].mn;
int mn = 1e9 + 7;
if(ql <= mid) mn = min(mn, query_min(lc, ql, qr));
if(qr > mid) mn = min(mn, query_min(rc, ql, qr));
return mn;
}

void solve() {
int n; cin >> n;
for(int i = 1;i <= n; i++) {
cin >> a[i].x >> a[i].h;
b[i] = a[i].x;
}
sort(b + 1, b + n + 1);
for(int i = 1;i <= n; i++) {
idx[i] = lower_bound(b + 1, b + n + 1, a[i].x) - b;
h[idx[i]] = a[i].h;
}
build(1, 1, n);
for(int i = 1;i <= n; i++) {
int pos = idx[i];
/*------查找左边1-pos--------*/
int lx = query_max(1, 1, pos);
if(lx > h[pos]) {
int l = 1, r = pos, ans = 0;
while(l <= r) {
int m = (l + r) / 2;
lx = query_max(1, m, pos);
if(lx > h[pos]) ans = m, l = m + 1;
else r = m - 1;
}
h[ans] = h[pos]; modify(1, ans, h[pos]);
}
if(pos == n) continue;
/*---------查找右边pos+1-n-----------*/
int rx = query_max(1, pos + 1, n);
if(rx <= h[pos]) {
rx = query_min(1, pos + 1, n);
int l = pos + 1, r = n, ans = 0;
while(l <= r) {
int m = (l + r) / 2;
int nrx = query_min(1, pos + 1, m);
if(nrx == rx) ans = m, r = m - 1;
else l = m + 1;
}
h[ans] = h[pos]; modify(1, ans, h[pos]);
}
}
for(int i = 1;i <= n; i++) cout << h[idx[i]] << " ";
cout << endl;
}

signed main() {
solve();
}

本文作者:jujimeizuo
本文地址https://blog.jujimeizuo.cn/2021/05/07/nowcoder-beginner28-e/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!