Solution S o l u t i o n
先看这个部分分。显然是个暴力DP。
设
dpi,x
d
p
i
,
x
表示考虑了前
i
i
个矩形,第个左端点在
x
x
的最优解。
转移就是
很通过简单的数学归纳,容易发现前面是一个一堆斜率递增的折线构成的函数,后面是一个
∨
∨
一样的函数。。。
进一步分析前面就是把 dpi−1,∗ d p i − 1 , ∗ 斜率小于 0 0 的向左平移,大于 0 0 的向右平移。
受到这个的启发,刚开始想打一个可并堆,发现其实没必要。
因为第二个函数很简单并且每次只合并 1 1 次,所以最后拐点的个数是的。只需要用堆暴力维护左右折线的拐点,暴力合并就好了。
#include <bits/stdc++.h>
#define show(x) cerr << #x << " = " << x << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> Pairs;
const int N = 202020;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
template<typename T>
inline void read(T &x) {
static char c; x = 0; int sgn = 0;
for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
if (sgn) x = -x;
}
int n;
ll addl, addr, ans;
int l[N], r[N];
priority_queue<ll> L;
priority_queue<ll, vector<ll>, greater<ll> > R;
template<typename T>
inline T Abs(T x) {
return x < 0 ? -x : x;
}
int main(void) {
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
read(n);
for (int i = 1; i <= n; i++) {
read(l[i]); read(r[i]);
if (i == 1) {
L.push(l[i]); R.push(l[i]);
addl = addr = 0;
continue;
}
int len2 = r[i] - l[i], len1 = r[i - 1] - l[i - 1];
addl -= len2;
addr += len1;
ll lb = L.top() + addl, rb = R.top() + addr;
if (l[i] < lb) {
ans += Abs(lb - l[i]);
R.push(lb - addr);
L.push(l[i] - addl);
L.push(l[i] - addl);
L.pop();
} else if (l[i] > rb) {
ans += Abs(rb - l[i]);
L.push(rb - addl);
R.push(l[i] - addr);
R.push(l[i] - addr);
R.pop();
} else {
L.push(l[i] - addl);
R.push(l[i] - addr);
}
}
cout << ans << endl;
return 0;
}