P2605 [ZJOI2010]基站选址
P2605 [ZJOI2010]基站选址
线段树优化 dp
。
记 表示第 位置建第 个基站的最小费用。
则有:,其中 表示 两点间没有基站的赔偿费用。
另,要在 位置建立一个费用为 ,覆盖距离为 的基站,起到统计答案的作用。
时间复杂度 。
考虑优化,发现 即区间最小值,可用线段树优化。
记 分别表示在区间 的点的最小及最大编号。
若当前枚举的点 ,那么线段树上区间 加上 。
因为后面的点要是从 的点转移,那么 就无法被覆盖到,所以要加上赔偿费用。
最后区间查询最小值即可。
时间复杂度 。
具体见代码。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int _ = 2e4 + 10, inf = 2e18;
int n, k, d[_], c[_], s[_], w[_];
int st[_], ed[_];
vector<int> D[_];
int tr[_ << 2], tag[_ << 2];
int f[_];
void build(int o, int l, int r)
{
tag[o] = 0;
if(l == r)
{
tr[o] = f[l];
return;
}
int mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
tr[o] = min(tr[o << 1], tr[o << 1 | 1]);
}
void update(int o, int l, int r, int L, int R, int val)
{
if(L > R) return;
if(L <= l && r <= R)
{
tr[o] += val, tag[o] += val;
return;
}
int mid = (l + r) >> 1;
if(L <= mid) update(o << 1, l, mid, L, R, val);
if(R > mid) update(o << 1 | 1, mid + 1, r, L, R, val);
tr[o] = min(tr[o << 1], tr[o << 1 | 1]) + tag[o];
}
int query(int o, int l, int r, int L, int R, int v)
{
if(L > R) return inf;
if(L <= l && r <= R)
return tr[o];
int mid = (l + r) >> 1, res = 0;
if(L <= mid) res = query(o << 1, l, mid, L, R, v + tag[o]);
if(R > mid) res = min(res, query(o << 1 | 1, mid + 1, r, L, R, v + tag[o]));
return res;
}
signed main()
{
scanf("%lld%lld", &n, &k);
d[1] = 0;
for(int i = 2; i <= n; ++i) scanf("%lld", &d[i]);
for(int i = 1; i <= n; ++i) scanf("%lld", &c[i]);
for(int i = 1; i <= n; ++i) scanf("%lld", &s[i]);
for(int i = 1; i <= n; ++i) scanf("%lld", &w[i]);
n++, k++;
d[n] = w[n] = inf;
for(int i = 1; i <= n; ++i)
{
st[i] = lower_bound(d + 1, d + n + 1, d[i] - s[i]) - d;
ed[i] = lower_bound(d + 1, d + n + 1, d[i] + s[i]) - d;
if(d[ed[i]] > d[i] + s[i]) ed[i]--;
D[ed[i]].push_back(i);
}
int now = 0;
for(int i = 1; i <= n; ++i)
{
f[i] = now + c[i];
for(int j : D[i])
now += w[j];
}
int ans = f[n];
for(int i = 2; i <= k; ++i)
{
build(1, 1, n);
for(int j = 1; j <= n; ++j)
{
f[j] = query(1, 1, n, 1, j - 1, 0) + c[j];
for(int k : D[j])
update(1, 1, n, 1, st[k] - 1, w[k]);
}
ans = min(ans, f[n]);
}
printf("%lld\n", ans);
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122013