@ZCDHJ
2019-08-03T14:56:01.000000Z
字数 2602
阅读 475
未分类
的 DP 很简单,设 为第 个村庄建造第 个基站,只考虑前 个村庄的花费。 其中 表示 与 中间的村庄需要赔偿的总额。考虑在 逐渐变大的时候,如果有一个村庄的可被覆盖范围 满足 ,以后的所有 都会加一。这个是一个区间加的形式,可以用线段树来维护每个 , 就是每次不断增大的状态中的第二个变量。每个区间只会被用作加法一次(在一个阶段内),所以总复杂度为 。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int MAXN = 2e4;
const int MAXK = 1e2;
int n, K, ans;
int c[MAXN | 1], dp[MAXK | 1][MAXN | 1], sum[MAXN | 1];
LL d[MAXN | 1];
struct Range {
int l, r;
LL w;
Range() : l(0), r(0), w(0) {}
friend bool operator< (const Range &lhs, const Range &rhs) {
return lhs.r < rhs.r;
}
} range[MAXN | 1];
inline int read() {
register int x = 0;
register char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}
void find(int x) {
int l, r, mid;
l = 1;
r = x;
while (l <= r) {
mid = (l + r) >> 1;
if (d[x] - d[mid] <= range[x].w) {
r = mid - 1;
range[x].l = mid;
} else l = mid + 1;
}
l = x;
r = n;
while (l <= r) {
mid = (l + r) >> 1;
if (d[mid] - d[x] <= range[x].w) {
l = mid + 1;
range[x].r = mid;
} else r = mid - 1;
}
}
struct Node {
int minv, lazy;
Node *ch[2];
Node() : minv(0), lazy(0) {
ch[0] = ch[1] = NULL;
}
} *root;
void pushUp(Node *o) {
o -> minv = std::min(o -> ch[0] -> minv, o -> ch[1] -> minv);
}
void pushDown(Node *o) {
if (o -> lazy != 0) {
o -> ch[0] -> minv += o -> lazy;
o -> ch[1] -> minv += o -> lazy;
o -> ch[0] -> lazy += o -> lazy;
o -> ch[1] -> lazy += o -> lazy;
o -> lazy = 0;
}
}
void build(Node *&o, int l, int r, int id) {
if (o == NULL) o = new Node;
else o -> lazy = 0;
if (l == r) {
o -> minv = dp[id][l];
o -> lazy = 0;
return;
}
int mid = (l + r) >> 1;
build(o -> ch[0], l, mid, id);
build(o -> ch[1], mid + 1, r, id);
pushUp(o);
}
void modify(Node *o, int l, int r, int ql, int qr, int v) {
if (ql <= l && r <= qr) {
o -> minv += v;
o -> lazy += v;
return;
}
int mid = (l + r) >> 1;
pushDown(o);
if (ql <= mid) modify(o -> ch[0], l, mid, ql, qr, v);
if (mid < qr) modify(o -> ch[1], mid + 1, r, ql, qr, v);
pushUp(o);
}
int query(Node *o, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return o -> minv;
int mid = (l + r) >> 1, res = 1e9;
pushDown(o);
if (ql <= mid) res = query(o -> ch[0], l, mid, ql, qr);
if (mid < qr) res = std::min(res, query(o -> ch[1], mid + 1, r, ql, qr));
return res;
}
int main() {
n = read();
K = read();
build(root, 1, n, 0);
for (int i = 2; i <= n; ++i) scanf("%lld", d + i);
for (int i = 1; i <= n; ++i) c[i] = read();
for (int i = 1; i <= n; ++i) {
scanf("%lld", &range[i].w);
find(i);
}
for (int i = 1; i <= n; ++i) range[i].w = read();
d[++n] = 1e9;
ans = 1e9;
int pot = 1;
++K;
for (int i = 1; i <= n; ++i) {
dp[1][i] = c[i];
for (int j = 1; j < i; ++j) if (range[j].l > i || range[j].r < i) dp[1][i] += range[j].w;
}
ans = dp[1][n];
std::sort(range + 1, range + 1 + n);
for (int i = 2; i <= K; ++i) {
build(root, 1, n, i - 1);
memset(sum, 0, sizeof(sum));
pot = 1;
for (int j = i; j <= n; ++j) {
while (pot <= n && range[pot].r < j) {
if (i <= range[pot].l) modify(root, 1, n, i - 1, range[pot].l - 1, range[pot].w);
++pot;
}
dp[i][j] = query(root, 1, n, i - 1, j - 1) + c[j];
}
ans = std::min(ans, dp[i][n]);
}
printf("%d\n", ans);
return 0;
}