在有 n 个水平平台的空间释放铁球,不能无承接坠落超过 h,求最短距离。
经典的单调性背景,不难想,但是细节超多,改了很久。在此提醒自己注意:
- zkw 线段树须额外判定空区间1,否则会死循环
- 离散化应在整个程序逆运算,若一部分要排序,可保留并始终取用索引
- 不要忘记题设(最大高度)
- 算法涉及无穷时,应在所有出口处理
#include <iostream>
#include <utility>
#include <algorithm>
#define cl(x) (2 * (x))
#define cr(x) (cl(x) + 1)
const int oxis = 100007;
int n, h, x, nhor = 0, undis[2 * oxis], nseg = 1;
int lb[oxis], rb[oxis], ldp[oxis], rdp[oxis];
int seg[0x80000];
std::pair<int, int> hors[2 * oxis], hs[oxis];
template <typename T>
void setmax(T &u, const T &v)
{
if (u < v)
u = v;
}
void input()
{
int y;
std::ios::sync_with_stdio(false);
std::cin >> n >> h >> x >> y;
for (int i = 0; i < n; ++i) {
int hi, l, r;
std::cin >> hi >> l >> r;
if (l == r || hi > y) {
n--;
i--;
continue;
}
hs[i].first = hi;
hors[cl(i)].first = l;
hors[cr(i)].first = r;
}
hors[cl(n)].first = hors[cr(n)].first = x;
hs[n++].first = y;
}
void discretation()
{
int cnt = 0;
for (int i = 0; i < n; ++i) {
hs[i].second = i;
hors[cl(i)].second = cl(i);
hors[cr(i)].second = cr(i);
}
std::sort(hs, hs + n + 1);
int twon = 2 * n, last = 0;
std::sort(hors, hors + twon);
for (int i = 0; i < twon; ++i) {
if (last != hors[i].first)
undis[++cnt] = last = hors[i].first;
hors[i].first = cnt;
}
std::sort(hors, hors + twon,
[](std::pair<int, int> a, std::pair<int, int> b) {
return a.second < b.second;
});
while (nseg <= cnt)
nseg *= 2;
}
void getBottom()
{
for (int i = 1; i <= n; ++i) {
int lk = hors[cl(hs[i].second)].first + nseg;
int rk = hors[cr(hs[i].second)].first + nseg;
for (int j = lk; j; j >>= 1)
setmax(lb[i], seg[j]);
for (int j = rk; j; j >>= 1)
setmax(rb[i], seg[j]);
if (lk == rk)
continue;
for (/* XXX */; lk ^ rk ^ 1; lk >>= 1, rk >>= 1) {
if (!(lk & 1))
seg[lk ^ 1] = i;
if ( rk & 1)
seg[rk ^ 1] = i;
}
}
}
const int INF = 0x7fffffff;
int solveSingle(int x, int y, int to)
{
if (to == 0)
return y > h ? INF : y;
if (y - hs[to].first > h)
return INF;
int hts = hs[to].second;
int lv = ldp[to] == INF ? INF :
undis[x] - undis[hors[cl(hts)].first] + ldp[to];
int rv = rdp[to] == INF ? INF :
undis[hors[cr(hts)].first] - undis[x] + rdp[to];
if (lv == INF && rv == INF)
return INF;
return y - hs[to].first + std::min(lv, rv);
}
void solve()
{
for (int i = 1; i <= n; ++i) {
ldp[i] = solveSingle(
hors[cl(hs[i].second)].first, hs[i].first, lb[i]);
rdp[i] = solveSingle(
hors[cr(hs[i].second)].first, hs[i].first, rb[i]);
}
int lv = ldp[n] == INF ? INF :
x - undis[hors[cl(hs[n].second)].first] + ldp[n];
int rv = rdp[n] == INF ? INF :
undis[hors[cr(hs[n].second)].first] - x + rdp[n];
std::cout << std::min(lv, rv) << std::endl;
}
int main()
{
input();
discretation();
getBottom();
solve();
return 0;
}
-
题目有空区间情况较少,但本题区间修改是开区间。 ↩