[ZJOI2010]基站选址,线段树优化DP
G. base 基站选址
题目描述
有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。
输入格式
输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述。 第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。 第三行包含N个整数,表示C1,C2,…CN。 第四行包含N个整数,表示S1,S2,…,SN。 第五行包含N个整数,表示W1,W2,…,WN。
输出格式
输出文件中仅包含一个整数,表示最小的总费用。
样例
样例输入
3 2 1 2 2 3 2 1 1 0 10 20 30
样例输出
4
数据范围与提示
40%的数据中,N<=500; 100%的数据中,K<=N,K<=100,N<=20,000,Di<=1000000000,Ci<=10000,Si<=1000000000,Wi<=10000。
1.lazy标记打错了,应该是 += ,不能直接覆盖
2.lc<<1 打成了 >>1 ,调了半天
3.优化思路:首先是每个村庄的左右端点,二分查找并记录
DP方程 f[i][j]=min(f[k][j-1]+pay[x])+c[i],表示第 j 个基站建在第 i 个村庄时的最小花费,不考虑 i+1 到 n
显然,可以去掉一维
f[i]=min(f[i]+pay[x])+c[i];
此时,考虑优化计算 pay[x] ,也就是没有被覆盖的点的花费
因为若 ed[x]=i,此时 i 不被选择,那么 计算 i+1 时就要加上花费
所以,我们应维护一个区间,存储上一个基站建在 i 时的最小花费之和 ,即 f[k][j-1]+pay[x];
在计算时,查找 [1,i-1]的最小值
然后更新所有以 i 为右端点的村庄的花费,区间为 [1,st[x]-1];
最后,因为我们考虑的是当前点对前面的影响,所以我们在最后新建一个假点,用来保存结果
代码:
#include<bits/stdc++.h>
#define re register int
#define int long long
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
const int N=2e4+10;
const int INF=1e12+7;
int n,k,tot,num;
int dis[N],c[N],s[N],w[N],st[N],ed[N];
struct TREE
{
int zh,lazy;
}use[N*40];
long long f[N];
int to[N<<1],next[N<<1],head[N<<1];
void add(int x,int y)
{
to[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
void pp(int p)
{
use[p].zh=min(use[lc].zh,use[rc].zh);
}
void pd(int p)
{
if(!use[p].lazy)
return;
use[lc].lazy+=use[p].lazy;
use[rc].lazy+=use[p].lazy;
use[lc].zh+=use[p].lazy;
use[rc].zh+=use[p].lazy;
use[p].lazy=0;
}
void build(int p,int l,int r)
{
use[p].lazy=0;
if(l==r)
{
use[p].zh=f[l];
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pp(p);
}
int query(int p,int L,int R,int l,int r)
{
if(l>r)
return INF;
if(l<=L&&R<=r)
return use[p].zh;
int mid=(L+R)>>1;
int ans=INF;
pd(p);
if(l<=mid)
ans=min(ans,query(lc,L,mid,l,r));
if(mid<r)
ans=min(ans,query(rc,mid+1,R,l,r));
return ans;
}
void change(int p,int L,int R,int l,int r,int z)
{
if(l>r)
return;
if(l<=L&&R<=r)
{
use[p].zh+=z;
use[p].lazy+=z;
return;
}
int mid=(L+R)>>1;
pd(p);
if(l<=mid)
change(lc,L,mid,l,r,z);
if(mid<r)
change(rc,mid+1,R,l,r,z);
pp(p);
}
signed main()
{
scanf("%lld%lld",&n,&k);
for(re i=2;i<=n;i++)
scanf("%lld",&dis[i]);
for(re i=1;i<=n;i++)
scanf("%lld",&c[i]);
for(re i=1;i<=n;i++)
scanf("%lld",&s[i]);
for(re i=1;i<=n;i++)
scanf("%lld",&w[i]);
++n;
++k;
dis[n]=INF;
w[n]=INF;
for(re i=1;i<=n;i++)
{
st[i]=lower_bound(dis+1,dis+n+1,max(dis[i]-s[i],0*1ll))-dis;
ed[i]=upper_bound(dis+1,dis+n+1,min(dis[i]+s[i],dis[n]))-dis;
ed[i]-=1;
add(ed[i],i);
}
int sum=0;
for(re i=1;i<=n;i++)
{
f[i]=sum+c[i];
for(re j=head[i];j;j=next[j])
sum+=w[to[j]];
}
int out=f[n];
for(re i=2;i<=k;i++)
{
build(1,1,n);
for(re j=1;j<=n;j++)
{
f[j]=query(1,1,n,1,j-1)+c[j];
for(re k=head[j];k;k=next[k])
{
int p=to[k];
change(1,1,n,1,st[p]-1,w[p]);
}
}
out=min(out,f[n]);
}
printf("%lld\n",out);
}
[ZJOI2010]基站选址,线段树优化DP的更多相关文章
- 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$
正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...
- luogu P2605 [ZJOI2010]基站选址 线段树优化dp
LINK:基站选址 md气死我了l达成1结果一直调 显然一个点只建立一个基站 然后可以从左到右进行dp. \(f_{i,j}\)表示强制在i处建立第j个基站的最小值. 暴力枚举转移 复杂度\(n\cd ...
- BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)
题目大意:略 洛谷题面传送门 BZOJ题面传送门 注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了 定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一 ...
- 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中间的不能被满足的村庄的赔偿金之 ...
- BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- Codeforces Round #426 (Div. 2) D 线段树优化dp
D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...
- BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】
BZOJ2090: [Poi2010]Monotonicity 2[线段树优化DP] Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. ...
- [AGC011F] Train Service Planning [线段树优化dp+思维]
思路 模意义 这题真tm有意思 我上下楼梯了半天做出来的qwq 首先,考虑到每K分钟有一辆车,那么可以把所有的操作都放到模$K$意义下进行 这时,我们只需要考虑两边的两辆车就好了. 定义一些称呼: 上 ...
- 【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp
题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a varian ...
随机推荐
- Spring Boot 2.x基础教程:使用Redis的发布订阅功能
通过前面一篇集中式缓存的使用教程,我们已经了解了Redis的核心功能:作为K.V存储的高性能缓存. 接下来我们会分几篇来继续讲讲Redis的一些其他强大用法!如果你对此感兴趣,一定要关注收藏我哦! 发 ...
- golang中的defer和return的执行顺序
结论 go中是先给return准备返回值,再根据defer先进后出的规则执行,最后将返回值返回给调用者 测试用例1验证分析 代码片段如下: func foo_1() (err error) { def ...
- .NET Core/.NET5/.NET6 开源项目汇总9:客户端跨平台UI框架
系列目录 [已更新最新开发文章,点击查看详细] .NET Core 实现了跨平台,支持在 Windwos.Linux.macOS上开发与部署,但是也仅限于Web应用程序.对于Windows桌面 ...
- 一文带你了解.Net信号量
本文主要讲解.Net基于Semaphore带大家了解信号量 信号量举例 大家去银行去银行取钱,互斥锁管理的时一个柜台是否正在处理业务,而信号量管理的是整个柜台是否正在处理业务,每当有一个柜台处理完成之 ...
- 【Linux】通过shell脚本对mysql的增删改查以及my.cnf的配置
目录 shell操作mysql 1.获取mysql默认密码 2.修改my.cnf文件 3.shell创建mysql数据库 4.shell创建mysql表 5.shell添加数据 6.shell删除数据 ...
- 29、vi和vim用法详解
vi类似于windows中的文本文件,用于普通的文本文件 vim:专家版的文件编辑器,用于shell程序型文件,带颜色,自检查语法 一般模式快捷键 O:光标到一行的首 $:光标到一行的尾 H:光标到整 ...
- 24、配置Oracle下sqlplus历史命令的回调功能
24.1.前言: 1.在oracle服务器上使用默认的sqlplus写sql命令时,如果写错了一个字母需要修改时,是无法通过 退格键消除错误的字母的,只能另起一行,重新写sql语句,而且也不能通过键盘 ...
- JS刷新窗口的几种方式
浮层内嵌iframe及frame集合窗口,刷新父页面的多种方法 <script language=JavaScript> parent.location.reload(); ...
- web自动化页面元素不能键盘输入
一.背景 web自动化中存在一部分元素属性是readonly属性,导致我们在使用自动化代码的时候无法使用sendkeys()方法传入数据,以12306网站选择出发日期为例,见下图 二.json语句处理 ...
- POJ 2663 Tri Tiling dp 画图找规律
状态:d[i]代表n=i时的方案数. 状态转移方程:d[i]=d[i-2]+2*(d[i-2]+d[i-4]+-+d[0]) i只会为偶数,奇数情况不存在,d[0]=1 找状态转移方程的时候画图更好理 ...