原题传送门
显然可以枚举提到过的点
若一个点
,是一个跳板的终点,那么
一般地,有
这是个
的暴力
如何优化
可以按照
为第一关键字
为第二关键字排序
保证
升序,所以接下来只用管
的大小关系
令
用树状数组用
更新区间
的最小值
每次
可是 是 的级别,所以要离散化
Code:
#include <bits/stdc++.h>
#define maxn 200010
#define LL long long
using namespace std;
struct data{
int x, y, id, opt, dis;
}a[maxn];
int tot, tot1, p, b[maxn], c[maxn], n, m, pos[maxn];
LL tree[maxn], dp[maxn];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
bool cmp(data x, data y){ return x.x == y.x ? (x.y == y.y ? x.opt < y.opt : x.y < y.y) : x.x < y.x; }
int lowbit(int x){ return x & -x; }
void update(int x, LL y){ for (; x <= p; x += lowbit(x)) tree[x] = min(tree[x], y); }
LL query(int x){ LL s = 1e9; for (; x; x -= lowbit(x)) s = min(s, tree[x]); return s; }
int find(int x){
int l = 1, r = p, ans;
while (l <= r){
int mid = (l + r) >> 1;
if (c[mid] == x) return mid;
else if (c[mid] > x) r = mid - 1; else l = mid + 1;
}
}
int main(){
n = read(), m = read();
for (int i = 1; i <= m; ++i){
a[++tot].x = read(), a[tot].y = read(), a[tot].opt = 0, a[tot].id = i, a[tot].dis = a[tot].x + a[tot].y;
a[++tot].x = read(), a[tot].y = read(), a[tot].opt = 1, a[tot].id = i, a[tot].dis = a[tot].x + a[tot].y;
b[++tot1] = a[tot - 1].y, b[++tot1] = a[tot].y;
}
sort(b + 1, b + 1 + tot1);
b[0] = b[1] - 1;
for (int i = 1; i <= tot1; ++i)
if (b[i] != b[i - 1]) c[++p] = b[i], tree[p] = 1e10;
sort(a + 1, a + 1 + tot, cmp);
for (int i = 1; i <= tot; ++i) a[i].y = find(a[i].y);
update(1, 0);
LL ans = 1e10;
for (int i = 1; i <= tot; ++i){
if (!a[i].opt) pos[a[i].id] = i;
dp[i] = 1e10;
if (a[i].opt == 1) dp[i] = min(dp[i], dp[pos[a[i].id]]);
dp[i] = min(dp[i], query(a[i].y) + a[i].dis);
update(a[i].y, dp[i] - a[i].dis);
ans = min(ans, dp[i] - a[i].dis);
}
printf("%lld\n", ans + n + n);
return 0;
}