线段树优化dp

数组f[i][j]表示在前i个村庄内,第j个基站建在i处的最小费用

根据交线牛逼法和王鹤松式可得方程

f[i][j]=min(f[k][j−1]+cost(k,i))

cost(k,i)表示第i~k个村庄之间没有被基站覆盖的村庄所需的赔偿费用,计算费用的复杂度为O(n)

利用二分查找预处理每个位置的需求范围bef[i],beh[i]

之后就是利用线段树维护f[]+cost()的最小值,区间查询区间更新

当beh[x]=i,若i不建造,则加cost(可能存在很多x,前向星或vector存储)

Code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#define ls(k) k<<1
#define rs(k) k<<1|1
using namespace std;
const int N=20010,K=110;
int dis[N],s[N],w[N],c[N],f[N];
int n,m,bef[N],beh[N];
int tot=0,to[N<<1],head[N<<1],nxt[N<<1];
int mn[N<<2],lz[N<<2];
void Add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void up(int k)
{
mn[k]=min(mn[ls(k)],mn[rs(k)]);
}
void build(int k,int l,int r)
{
lz[k]=0;
if(l==r)
{
mn[k]=f[l];
return ;
}
int mid=l+r>>1;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
up(k);
}
void down(int k)
{
lz[ls(k)]+=lz[k];
lz[rs(k)]+=lz[k];
mn[ls(k)]+=lz[k];
mn[rs(k)]+=lz[k];
lz[k]=0;
}
int query(int k,int l,int r,int L,int R)
{
if(L>R)return 0x3f3f3f3f;
if(L<=l&&R>=r)return mn[k];
int mid=l+r>>1;
if(lz[k])down(k);
int res=0x3f3f3f3f;
if(L<=mid)res=min(res,query(ls(k),l,mid,L,R));
if(mid<R)res=min(res,query(rs(k),mid+1,r,L,R));
return res;
}
void change(int k,int l,int r,int L,int R,int vl)
{
if(L>R)return ;
if(L<=l&&R>=r)
{
lz[k]+=vl;
mn[k]+=vl;
return ;
}
if(lz[k])down(k);
int mid=l+r>>1;
if(L<=mid)change(ls(k),l,mid,L,R,vl);
if(R>mid)change(rs(k),mid+1,r,L,R,vl);
up(k);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=2;i<=n;i++)scanf("%d",&dis[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]);
n++,m++;
dis[n]=w[n]=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
bef[i]=lower_bound(dis+1,dis+n+1,dis[i]-s[i])-dis;
beh[i]=lower_bound(dis+1,dis+n+1,dis[i]+s[i])-dis;
if(dis[beh[i]]>dis[i]+s[i])beh[i]--;
Add(beh[i],i);
}
int now=0;
for(int j=1;j<=n;j++)
{
f[j]=now+c[j];
for(int i=head[j];i;i=nxt[i])now+=w[to[i]];
}
int ans=f[n];
for(int i=2;i<=m;i++)
{
build(1,1,n);
for(int j=1;j<=n;j++)
{
f[j]=query(1,1,n,1,j-1)+c[j];
for(int p=head[j];p;p=nxt[p])
change(1,1,n,1,bef[to[p]]-1,w[to[p]]);
}
ans=min(ans,f[n]);
}
cout<<ans<<endl;
return 0;
}

最新文章

  1. .Net语言 APP开发平台——Smobiler学习日志:如何快速实现类似于微信的悬浮显示二维码效果
  2. AlloyRenderingEngine继承
  3. com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process &#39;command &#39; finished with non-zero exit value 1
  4. Linux上USB移植错误解决笔记
  5. c#Ice开发之环境配置(一)
  6. 如何解决虚拟机Mac OS X 不支持二进制编译问题()
  7. 转载:scikit-learn学习之SVM算法
  8. HDU 4287 Intelligent IME(string,map,stl,make_pair)
  9. [GUI]界面开发类库
  10. 一些基础的.net用法
  11. js中获取时间new date()的用法
  12. 类的命名空间&amp;组合
  13. 13. Redis监控运维云平台CacheCloud
  14. TZOJ 4244 Sum(单调栈区间极差)
  15. 判断input checkbox选中
  16. 文字和img、input并排无法对齐的问题
  17. Web系统自己主动化部署脚本
  18. Array遍历的小技巧
  19. No persister for nhibernate 解决下面的问题
  20. Token-Pasting Operator (##) and Stringizing Operator (#)

热门文章

  1. ssh_整合总结
  2. springCloud学习-服务的注册与发现(Eureka)
  3. nyoj_114_某种序列_201403161700
  4. [转]十五天精通WCF——第二天 告别烦恼的config配置
  5. Zend_Form 创建、校验和解析表单的基础--(手冊)
  6. 使用jQuery.makeArray() 将多种类型转换成JS原生Array
  7. 从头认识java-15.2 Collection的经常用法(2)-注意点
  8. C++中的inline的用法
  9. 82.角色管理Extjs 页面
  10. vs2010永久删除项目的相关操作