LuoguP2605 [ZJOI2010]基站选址 线段树优化DP
比较好的一道题 DP 题.
令 $f[i][j]$ 表示覆盖前 $i$ 个基站且 $i$ 位置上维修了基站的最小代价.
注意:上面设的状态是不考虑 $[i+1,n]$ 的.
转移的话 $f[i][j] \leftarrow f[k][j-1]+calc(j-1,i)$.
其中 $calc(i,j)$ 表示 $i$ 和 $j$ 分别修了基站的情况下 $i,j$ 之间需要用 $W_{i}$ 的总和.
然后这个 $calc(i,j)$ 可以在枚举 $j$ 的时候在线段树上更新.
即对于每个位置记录其被管辖范围 $[l,r]$ 然后扫描到 $r+1$ 时将 $[0,l-1]$ 做一个区间加法即可.
空间复杂度 $O(n)$,时间复杂度 $O(Kn \log n)$.
code:
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define N 20009
#define ll long long
#define lson now<<1
#define rson now<<1|1
#define pb push_back
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
const int inf=1000000009;
int n,K;
int left[N],right[N],f[N];
int mn[N<<2],lazy[N<<2],dis[N],cost[N],si[N],wi[N];
vector<int>g[N];
inline void pushup(int now) {
mn[now]=min(mn[lson],mn[rson]);
}
inline void mark(int now,int v) {
mn[now]+=v,lazy[now]+=v;
}
inline void pushdown(int now) {
if(lazy[now]) {
mark(lson,lazy[now]);
mark(rson,lazy[now]);
lazy[now]=0;
}
}
void build(int l,int r,int now) {
lazy[now]=0;
if(l==r) {
mn[now]=f[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
pushup(now);
}
int query(int l,int r,int now,int L,int R) {
if(l>=L&&r<=R) {
return mn[now];
}
pushdown(now);
int mid=(l+r)>>1,re=inf;
if(L<=mid) re=min(re,query(l,mid,lson,L,R));
if(R>mid) re=min(re,query(mid+1,r,rson,L,R));
return re;
}
void update(int l,int r,int now,int L,int R,int v) {
if(l>=L&&r<=R) {
mark(now,v);
return;
}
pushdown(now);
int mid=(l+r)>>1;
if(L<=mid) update(l,mid,lson,L,R,v);
if(R>mid) update(mid+1,r,rson,L,R,v);
pushup(now);
}
int main() {
// setIO("input");
scanf("%d%d",&n,&K);
dis[1]=0;
for(int i=2;i<=n;++i) scanf("%d",&dis[i]);
for(int i=1;i<=n;++i) scanf("%d",&cost[i]);
for(int i=1;i<=n;++i) scanf("%d",&si[i]);
for(int i=1;i<=n;++i) scanf("%d",&wi[i]);
++n,++K,cost[n]=0,wi[n]=inf;
for(int i=1;i<n;++i) {
int l,r,mid,ans;
ans=i,l=1,r=i-1;
while(l<=r) {
mid=(l+r)>>1;
if(dis[i]-si[i]<=dis[mid]) {
ans=mid;
r=mid-1;
}
else l=mid+1;
}
left[i]=ans;
ans=i,l=i,r=n-1;
while(l<=r) {
mid=(l+r)>>1;
if(dis[i]+si[i]>=dis[mid]) {
ans=mid;
l=mid+1;
}
else r=mid-1;
}
right[i]=ans;
g[right[i]].pb(i);
}
int ans=inf;
for(int j=1;j<=K;++j) {
if(j==1) {
int tot=0;
for(int i=1;i<=n;++i) {
f[i]=tot+cost[i];
for(int j=0;j<g[i].size();++j) {
tot+=wi[g[i][j]];
}
}
ans=min(ans,f[n]);
}
else {
build(0,n,1);
for(int i=1;i<=n;++i) {
f[i]=query(0,n,1,0,i-1)+cost[i];
for(int j=0;j<g[i].size();++j) {
int p=g[i][j];
update(0,n,1,0,left[p]-1,wi[p]);
}
}
ans=min(ans,f[n]);
}
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号