【BZOJ1835】基站选址(线段树)

题面

BZOJ

题解

考虑一个比较暴力的\(dp\)

设\(f[i][j]\)表示建了\(i\)个基站,最后一个的位置是\(j\)的最小代价

考虑如何转移\(f[i][j]=min(f[i-1][p]+Cost(p+1,j)+C[j])\)

其中\(Cost\)表示代价,也就是区间内所有没有被覆盖的村庄的\(W\)的和

如果直接暴力\(dp\),复杂度\(O(n^2k)\),这个复杂度还假设了\(Cost\)是\(O(1)\)计算的

转移的时候是枚举建造的个数,显然还可以滚调第一维

但是这个复杂度我们无法接受,我们要思考有没有更快的方法

考虑\(dp\)的转移式子

\(f[i][j]=min(f[i-1][p]+Cost(p+1,j)+C[j])\)

\(f[i][j]=min(f[i-1][p]+Cost(p+1,j))+C[j]\)

相当于我们要找到的就是\(min(f[i-1][p]+Cost(p+1,j))\)

我们不难知道,如果一个村庄不需要贡献他的\(W\)

那么,必须在一个区间内存在一个基站

所以,这个区间我们可以提前预处理出来(二分一下)

然后按照右端点排序,按照右端点结束的位置分类

从左到右这样扫过来,如果过了某个右端点

此时,这些区间的最右端在当前位置的那些村落,

在后面的\(dp\)中必然产生贡献,

会对\([1,left-1]\)的所有区间都产生\(W\)的贡献

因此在线段树上做一次区间加法

每次进行转移的时候从所有的位置中选出区间最小值就行了

然后\(K\)增大,重构线段树即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define RG register
#define ll long long
#define MAX 30000
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int f[MAX];
struct Node{int v,tag;}t[MAX<<2];
struct Seg{int l,r;}p[MAX];
vector<int> V[MAX];
int n,K,W[MAX],S[MAX],d[MAX],C[MAX],ans=2e9;
void Build(int now,int l,int r)
{
t[now].tag=0;
if(l==r){t[now].v=f[l];return;}
int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
t[now].v=min(t[lson].v,t[rson].v);
}
void puttag(int now,int w){t[now].v+=w;t[now].tag+=w;}
void pushdown(int now)
{
puttag(lson,t[now].tag);
puttag(rson,t[now].tag);
t[now].tag=0;
}
void Modify(int now,int l,int r,int L,int R,int w)
{
if(L>R)return;
if(L<=l&&r<=R){puttag(now,w);return;}
pushdown(now);
int mid=(l+r)>>1;
if(L<=mid)Modify(lson,l,mid,L,R,w);
if(R>mid)Modify(rson,mid+1,r,L,R,w);
t[now].v=min(t[lson].v,t[rson].v);
}
int Query(int now,int l,int r,int L,int R)
{
if(L>R)return 0;
if(L<=l&&r<=R)return t[now].v;
pushdown(now);
int mid=(l+r)>>1,ret=2e9;
if(L<=mid)ret=min(ret,Query(lson,l,mid,L,R));
if(R>mid)ret=min(ret,Query(rson,mid+1,r,L,R));
return ret;
}
int main()
{
n=read();K=read();
for(int i=2;i<=n;++i)d[i]=read();
for(int i=1;i<=n;++i)C[i]=read();
for(int i=1;i<=n;++i)S[i]=read();
for(int i=1;i<=n;++i)W[i]=read();
for(int i=1,l,r,pos;i<=n;++i)
{
l=1,r=i-1,pos=i;
while(l<=r)
{
int mid=(l+r)>>1;
if(d[i]-d[mid]>S[i])l=mid+1;
else pos=mid,r=mid-1;
}
p[i].l=pos;
l=i+1,r=n,pos=i;
while(l<=r)
{
int mid=(l+r)>>1;
if(d[mid]-d[i]>S[i])r=mid-1;
else pos=mid,l=mid+1;
}
p[i].r=pos;
}
for(int i=1;i<=n;++i)
V[p[i].r].push_back(i);
for(int i=1,tmp=0;i<=n+1;++i)
{
f[i]=tmp+C[i];
for(int j=0;j<V[i].size();++j)
tmp+=W[V[i][j]];
}
ans=f[n+1];
for(int i=1;i<=K;++i)
{
Build(1,1,n+1);
for(int j=1;j<=n+1;++j)
{
f[j]=Query(1,1,n+1,1,j-1)+C[j];
for(int k=0;k<V[j].size();++k)
Modify(1,1,n+1,1,p[V[j][k]].l-1,W[V[j][k]]);
}
ans=min(ans,f[n+1]);
}
printf("%d\n",ans);
return 0;
}

【BZOJ1835】基站选址(线段树)的更多相关文章

  1. 【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP

    [BZOJ1835][ZJOI2010]base 基站选址 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯 ...

  2. [ZJOI2010]基站选址,线段树优化DP

    G. base 基站选址 内存限制:128 MiB 时间限制:2000 ms 标准输入输出 题目类型:传统 评测方式:文本比较   题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离 ...

  3. luogu2605 基站选址 (线段树优化dp)

    设f[i][j]表示在第i个村庄建第j个基站的花费 那么有$f[i][j]=min\{f[k][j-1]+w[k,i]\}$,其中w[k,i]表示在k,i建基站,k,i中间的不能被满足的村庄的赔偿金之 ...

  4. BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)

    题目大意:略 洛谷题面传送门 BZOJ题面传送门 注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了 定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一 ...

  5. 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$

    正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...

  6. luogu P2605 [ZJOI2010]基站选址 线段树优化dp

    LINK:基站选址 md气死我了l达成1结果一直调 显然一个点只建立一个基站 然后可以从左到右进行dp. \(f_{i,j}\)表示强制在i处建立第j个基站的最小值. 暴力枚举转移 复杂度\(n\cd ...

  7. BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)

    Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...

  8. P2605 [ZJOI2010]基站选址

    题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范 ...

  9. BZOJ1835 [ZJOI2010] 基站选址 【动态规划】【线段树】

    题目分析: 首先想一个DP方程,令f[m][n]表示当前在前n个村庄选了m个基站,且第m个基站放在n处的最小值,转移可以枚举上一个放基站的村庄,然后计算两个村庄之间的代价. 仔细思考两个基站之间村庄的 ...

随机推荐

  1. 我的第一个上线小程序,案例实战篇二——LayaAir游戏开始界面开发

    不知不觉我的第一个小程序已经上线一周了,uv也稳定的上升着. 很多人说我的小程序没啥用,我默默一笑,心里说:“它一直敦促我学习,敦促我进步”.我的以一个小程序初衷是经验分享,目前先把经验分享到博客园, ...

  2. CHAPTER 38 Reading ‘the Book of Life’ The Human Genome Project 第38章 阅读生命之书 人体基因组计划

    CHAPTER 38 Reading ‘the Book of Life’ The Human Genome Project 第38章 阅读生命之书 人体基因组计划 Humans have about ...

  3. Netty源码分析第7章(编码器和写数据)---->第1节: writeAndFlush的事件传播

    Netty源码分析第七章: 编码器和写数据 概述: 上一小章我们介绍了解码器, 这一章我们介绍编码器 其实编码器和解码器比较类似, 编码器也是一个handler, 并且属于outbounfHandle ...

  4. 用线性分类器实现预测鸢尾花的种类(python)

    这是个人学习时跑的代码,结果就不贴了,有需要的可以自己运行,仅供参考,有不知道的可以私下交流,有问题也可以联系我.当然了我也只能提供一点建议,毕竟我也只是初学者 第一个页面 # -*- coding: ...

  5. Binary Tree的3种非Recursive遍历

    Binary Tree Preorder Traversal Given a binary tree, return the preorder traversal of its nodes' valu ...

  6. Kubernetes探索学习004--深入Kubernetes的Pod

    深入研究学习Pod 首先需要认识到Pod才是Kubernetes项目中最小的编排单位原子单位,凡是涉及到调度,网络,存储层面的,基本上都是Pod级别的!官方是用这样的语言来描述的: A Pod is ...

  7. mongodb基本使用(四)

    MongoDB 条件操作符 描述 条件操作符用于比较两个表达式并从mongoDB集合中获取数据. MongoDB中条件操作符有: (>) 大于 - $gt (<) 小于 - $lt (&g ...

  8. Dao DaoImp

    DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可在模块中调用此接口 ...

  9. Thunder-Beta发布-事后诸葛亮会议-2017秋-软件工程第十一次作业

    小组名称:Thunder项目名称:爱阅APP小组成员:王航 李传康 翟宇豪 邹双黛 苗威 宋雨 胡佑蓉 杨梓瑞一.设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有 ...

  10. 实验三 敏捷开发与XP实践 实验报告 20135232王玥

    一.实验内容 1. XP基础 2. XP核心实践 3. 相关工具 二.实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2. ...