题解:Dp+线段树维护所有决策
f[i][j]表示第j个基站建在第i个位置,i之前的村庄与建基站的总费用的最小值
以j为阶段
枚举i,维护所有决策f[x][j-1];
当一个村庄q不能被i覆盖了,那么在1~p之间建立基站的决策费用要+c
p为q左边第一个不能覆盖q的村庄
复杂度O( nklogn);
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=20009;
const int inf=1000000000;
int n,m;
int ans=inf;
int f[maxn][109];
int d[maxn];
int c[maxn];
int w[maxn];
int s[maxn];
int Bl[maxn],Br[maxn];
vector<int>Tr[maxn],Tl[maxn];
struct SegmentTree{
int l,r,tag,mn;
}tree[maxn<<2];
inline void pushup(int now){
tree[now].mn=min(tree[now<<1].mn,tree[now<<1|1].mn);
}
inline void pushdown(int now){
if(tree[now].tag){
tree[now<<1].tag+=tree[now].tag;
tree[now<<1|1].tag+=tree[now].tag;
tree[now<<1].mn+=tree[now].tag;
tree[now<<1|1].mn+=tree[now].tag;
tree[now].tag=0;
}
}
void BuildTree(int now,int l,int r,int p){
tree[now].l=l;tree[now].r=r;tree[now].tag=0;
if(l==r){
tree[now].mn=f[l][p];
return;
}
int mid=(l+r)>>1;
BuildTree(now<<1,l,mid,p);
BuildTree(now<<1|1,mid+1,r,p);
pushup(now);
}
void Updatasec(int now,int ll,int rr,int x){
if(ll>rr)return;
if(tree[now].l>=ll&&tree[now].r<=rr){
tree[now].tag+=x;tree[now].mn+=x;return;
}
pushdown(now);
int mid=(tree[now].l+tree[now].r)>>1;
if(ll<=mid)Updatasec(now<<1,ll,rr,x);
if(rr>mid)Updatasec(now<<1|1,ll,rr,x);
pushup(now);
}
int Querymin(int now,int ll,int rr){
if(tree[now].l>=ll&&tree[now].r<=rr){
return tree[now].mn;
}
pushdown(now);
int mid=(tree[now].l+tree[now].r)>>1;
int ret=inf;
if(ll<=mid)ret=min(ret,Querymin(now<<1,ll,rr));
if(rr>mid)ret=min(ret,Querymin(now<<1|1,ll,rr));
return ret;
}
int main(){
scanf("%d%d",&n,&m);
d[1]=0;
for(int i=2;i<=n;++i)scanf("%d",&d[i]);
for(int i=1;i<=n;++i)scanf("%d",&c[i]);
for(int i=1;i<=n;++i)scanf("%d",&s[i]);
for(int i=1;i<=n;++i)scanf("%d",&w[i]);
for(int i=1;i<=n;++i){
int p,tmp;
tmp=d[i]+s[i];
p=lower_bound(d+1,d+1+n,tmp)-d;
if(tmp<=d[n]){
if(d[p]!=tmp)--p;
Tr[p].push_back(i);
Br[i]=p;
}else{
Br[i]=-1;
}
tmp=d[i]-s[i];
p=lower_bound(d+1,d+1+n,tmp)-d;
if(tmp>=0){
Tl[p].push_back(i);
Bl[i]=p;
}else{
Bl[i]=-1;
}
}
// for(int i=1;i<=n;++i){
// cout<<Bl[i]<<' '<<Br[i]<<endl;
// }
for(int tmp=0,i=1;i<=n;++i){
// cout<<"ASD"<<' '<<i<<' '<<tmp<<endl;
f[i][1]=tmp+c[i];
for(int j=0;j<Tr[i].size();++j){
int x=Tr[i][j];
tmp+=w[x];
// cout<<"eaint "<<tmp<<endl;
}
}
for(int j=2;j<=m;++j){
BuildTree(1,1,n,j-1);
for(int i=1;i<=j-1;++i)f[i][j]=inf;
for(int i=j;i<=n;++i){
f[i][j]=Querymin(1,1,i-1)+c[i];
for(int k=0;k<Tr[i].size();++k){
int x=Tr[i][k];
if(Bl[x]>1)Updatasec(1,1,Bl[x]-1,w[x]);
}
}
}
for(int tmp=0,i=n;i>=1;--i){
for(int j=1;j<=m;++j){
ans=min(ans,f[i][j]+tmp);
}
for(int j=0;j<Tl[i].size();++j){
int x=Tl[i][j];
tmp+=w[x];
}
}
// for(int j=1;j<=m;++j){
// for(int i=1;i<=n;++i){
// cout<<f[i][j]<<' ';
// }
// cout<<endl;
// }
cout<<ans<<endl;
return 0;
}