poj 2374
题意:给你$n$个围栏,对于每个围栏你必须走到其边上才可以往下跳,现在问你从初始最高位置的$n$个围栏,到原点,水平走过的路程最少是多少?
设$dp(i,0/1)$为前$i$个围栏在左/右的最短距离,则
$$
dp(i, 0)=\min(dp(a, 0) + |x_i - x_a|, dp(a, 1) + |x_i - y_a|) \\
dp(i, 1)=\min(dp(b, 0) + |y_i - x_b|, dp(b, 1) + |y_i - y_b|)
$$
其中$a,b$是这个围栏端点掉下去能掉到的围栏,这个可以用线段树染色维护。
知识点
1、线段树优化 DP 不一定是要维护最优值
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db long double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
const LL MAXN = 200000 + 5, INF = 4223372036854775808ll, BS = 100000;
LL n, s, x[MAXN], y[MAXN];
LL dp[MAXN][2];
LL abss(LL x) {return x > 0 ? x : -x;}
#define M ((l + r) >> 1)
#define lc (o << 1)
#define rc (o << 1 | 1)
LL col[MAXN * 4];
void pushdown(LL o, LL len) {
if (len == 1) return ;
if (col[o]) {
col[lc] = col[rc] = col[o];
col[o] = 0;
}
}
void build(LL o, LL l, LL r) {
col[o] = 0;
if (l == r) return ; else {
build(lc, l, M), build(rc, M + 1, r);
}
}
void update(LL o, LL l, LL r, LL x, LL y, LL v) {
pushdown(o, r - l + 1);
if (x <= l && r <= y) {
col[o] = v;
return ;
}
if (x <= M) update(lc, l, M, x, y, v);
if (M < y) update(rc, M + 1, r, x, y, v);
}
LL query(LL o, LL l, LL r, LL p) {
pushdown(o, r - l + 1);
if (l == r) return col[o];
if (p <= M) return query(lc, l, M, p);
return query(rc, M + 1, r, p);
}
void clean() {
dp[1][0] = dp[1][1] = 0;
for (LL i = 2; i <= n; ++i) dp[i][0] = dp[i][1] = INF;
}
int solve() {
clean();
scanf("%lld%lld", &n, &s);
s += BS;
build(1, 0, 200000);
x[0] = y[0] = BS;
for (LL i = 1; i <= n; ++i) {
scanf("%lld%lld", &x[i], &y[i]);
x[i] += BS, y[i] += BS;
LL a = query(1, 0, 200000, x[i]);
LL b = query(1, 0, 200000, y[i]);
dp[i][0] = min(dp[a][0] + abss(x[i] - x[a]), dp[a][1] + abss(x[i] - y[a]));
dp[i][1] = min(dp[b][0] + abss(y[i] - x[b]), dp[b][1] + abss(y[i] - y[b]));
update(1, 0, 200000, x[i], y[i], i);
}
printf("%lld\n", min(dp[n][0] + abss(s - x[n]), dp[n][1] + abss(s - y[n])));
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}