传送门: https://ac.nowcoder.com/acm/contest/16081/E
题意
- 登 山 顺 序 不 一 定 从 左 到 右 , 是 按 照 给 出 山 峰 的 顺 序 登山顺序不一定从左到右,是按照给出山峰的顺序 登山顺序不一定从左到右,是按照给出山峰的顺序
- 找 到 左 边 第 一 个 大 于 当 前 山 峰 的 山 峰 的 坐 标 , 修 改 它 找到左边第一个大于当前山峰的山峰的坐标,修改它 找到左边第一个大于当前山峰的山峰的坐标,修改它
- 如 果 右 边 没 有 大 于 当 前 山 峰 的 , 找 到 离 当 前 山 峰 最 近 的 最 矮 山 峰 , 修 改 它 如果右边没有大于当前山峰的,找到离当前山峰最近的最矮山峰,修改它 如果右边没有大于当前山峰的,找到离当前山峰最近的最矮山峰,修改它
思路
首 先 顺 序 是 按 照 给 出 的 山 峰 顺 序 , 并 且 x 坐 标 过 大 , 但 是 点 数 只 有 2 e 5 , 所 以 需 要 离 散 化 。 首先顺序是按照给出的山峰顺序,并且x坐标过大,但是点数只有2e5,所以需要离散化。 首先顺序是按照给出的山峰顺序,并且x坐标过大,但是点数只有2e5,所以需要离散化。
对
于
一
个
点
,
需
要
找
到
左
边
和
右
边
两
个
特
殊
要
求
的
山
峰
,
这
个
过
程
可
以
二
分
。
对于一个点,需要找到左边和右边两个特殊要求的山峰,这个过程可以二分。
对于一个点,需要找到左边和右边两个特殊要求的山峰,这个过程可以二分。
并
且
是
区
间
查
询
,
所
以
需
要
线
段
树
维
护
,
维
护
区
间
最
大
值
和
最
小
值
即
可
。
并且是区间查询,所以需要线段树维护,维护区间最大值和最小值即可。
并且是区间查询,所以需要线段树维护,维护区间最大值和最小值即可。
- 左 边 : 假 设 当 前 是 第 i 座 山 , 映 射 过 去 的 位 置 是 p o s ( 离 散 化 ) , 二 分 [ 1 , p o s ] 区 间 , 找 到 最 近 的 一 个 大 于 当 前 高 度 的 山 左边:假设当前是第i座山,映射过去的位置是pos(离散化),二分[1,pos]区间,找到最近的一个大于当前高度的山 左边:假设当前是第i座山,映射过去的位置是pos(离散化),二分[1,pos]区间,找到最近的一个大于当前高度的山
- 右 边 : 同 理 。 假 设 映 射 的 位 置 是 p o s , 先 求 出 区 间 [ p o s + 1 , n ] 的 最 大 值 判 断 需 不 需 要 修 改 。 若 是 需 要 , 则 二 分 [ p o s + 1 , n ] 区 间 , 找 到 最 近 的 一 个 最 小 值 右边:同理。假设映射的位置是pos,先求出区间[pos+1,n]的最大值判断需不需要修改。若是需要,则二分[pos+1,n] 区间,找到最近的一个最小值 右边:同理。假设映射的位置是pos,先求出区间[pos+1,n]的最大值判断需不需要修改。若是需要,则二分[pos+1,n]区间,找到最近的一个最小值
Code
#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();
}