写了暴力 DP 式子,然后埋头推斜率优化,然后发现它两维都不单增。
遂破防,把 $\min$ 内的式子展开,改成一个一次函数的形式,相当于全局插入线段求单点最小值。
这个李超树秒了,然后不会写李超树。
口胡了一个 长得很像李超树的 李超树之后发现它挂了,因为没有把路径上的所有线段求 $\min$。
然而它实际上就是李超树 /oh
于是愉快地获得了紫题++。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 15, M = 1e6 + 15;
const long long INF = 1e18;
int n, h[N], w[N];
long long s[N], dp[N];
long long k[N], b[N];
struct Lc_SegTree {
int l, r;
int id;
} tr[M << 2];
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r;
tr[u].id = 0;
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
}
long long val(int u, int x) {
if (u == 0) return INF;
return k[u] * 1ll * x + b[u];
}
void change(int u, int d) {
if (tr[u].l == tr[u].r) {
if (val(tr[u].id, tr[u].l) > val(d, tr[u].l)) tr[u].id = d;
return;
}
int l = tr[u].l, r = tr[u].r;
int mid = l + r >> 1;
if (val(tr[u].id, mid) > val(d, mid)) swap(tr[u].id, d);
if (val(tr[u].id, l) > val(d, l)) change(u << 1, d);
else if (val(tr[u].id, r) > val(d, r)) change(u << 1 | 1, d);
}
long long query(int u, int x) {
if (tr[u].l == tr[u].r) return val(tr[u].id, x);
int mid = tr[u].l + tr[u].r >> 1;
long long res = val(tr[u].id, x);
if (x <= mid) return min(res, query(u << 1, x));
else return min(res, query(u << 1 | 1, x));
}
int main() {
scanf("%d", &n);
int Max = 0;
for (int i = 1; i <= n; i++) scanf("%d", &h[i]), Max = max(Max, h[i]);
for (int i = 1; i <= n; i++) scanf("%d", &w[i]), s[i] = s[i - 1] + w[i];
build(1, 0, Max);
k[1] = -2ll * h[1], b[1] = h[1] * 1ll * h[1] - s[1];
change(1, 1);
for (int i = 2; i <= n; i++) {
dp[i] = s[i - 1] + h[i] * 1ll * h[i] + query(1, h[i]);
k[i] = -2ll * h[i], b[i] = dp[i] + h[i] * 1ll * h[i] - s[i];
change(1, i);
}
printf("%lld\n", dp[n]);
return 0;
}
怎么评论李超呢?这个东西碰上实在要卡的就废了。
我只写过这一次 qaq。
所以还没碰到被卡的情况
我太弱了不会李超,只会推鞋油式子