题解
他在到达平台左端点或者右端点之前都会保持一个状态不变化 所以只需要计算断点值 离散化端点值(我把左端点+1和右端点-1也离散化了更稳妥一些)
d[i]表示到达i这个位置的最短时间 p[i]表示到达i这个位置的最低高度 平台按照高度排序 如果高度差不会摔死则从上向下转移
d[左端点] = min(d[左端点], d[k] + h[i] - h[j] + k- 左端点) i为转移的平面 j为当前平面k从[左端点, 右端点] 右端点类似
AC代码
#include <vector>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e3 + 10;
int d[MAXN << 1], p[MAXN << 1]; //到i这个位置 最短时间 最低高度
vector<int> dz;
struct node
{
int x, y, h;
bool operator < (const node &oth) const
{
if (this->h != oth.h)
return this->h > oth.h;
if (this->x != oth.x)
return this->x < oth.x;
return this->y < oth.y;
}
}a[MAXN];
int Discrete(int v)
{
return lower_bound(dz.begin(), dz.end(), v) - dz.begin();
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int T;
cin >> T;
while (T--)
{
dz.clear();
dz.push_back(-INF);
int n, x, y, mx;
cin >> n >> x >> y >> mx;
for (int i = 0; i < MAXN << 1; i++)
d[i] = INF, p[i] = y;
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].h), dz.push_back(a[i].x), dz.push_back(a[i].x + 1), dz.push_back(a[i].y), dz.push_back(a[i].y - 1);
dz.push_back(x); //插入起点
sort(a + 1, a + n + 1);
sort(dz.begin(), dz.end());
dz.erase(unique(dz.begin(), dz.end()), dz.end());
d[Discrete(x)] = 0; //起点为0
for (int i = 1; i <= n; i++)
{
int l = Discrete(a[i].x), r = Discrete(a[i].y);
x = y = INF;
for (int j = l; j <= r; j++) //遮挡范围
{
if (p[j] - a[i].h <= mx)
{
x = min(x, dz[j] - a[i].x + p[j] - a[i].h + d[j]);
y = min(y, a[i].y - dz[j] + p[j] - a[i].h + d[j]);
}
d[j] = INF, p[j] = a[i].h; //刷新高度
}
d[l] = x, d[r] = y;
}
int ans = INF;
for (int i = 0; i < MAXN << 1; i++)
if (p[i] <= mx) //小于等于mx才可以计算
ans = min(ans, d[i] + p[i]);
cout << ans << endl;
}
return 0;
}