bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1835
【题意】
有n个村庄,每个村庄位于d[i],要求建立不多于k个基站,在第i个村庄建基站的费用为c[i],如果在距离村i不超过s[i]内有基站则该村被覆盖,村i不被覆盖的补偿费为w[i],求最少花费。
【思路】
设f[i][j]表示第i个村建第j个基站的最小花费,则有转移式:
f[i][j]=min{ f[k][j-1]+cost(k,i) } + c[i] ,j-1<=k<=i-1
cost(k,i)=sigma{ w[x] } k+1<=x<=i-1 , 且x未被覆盖
f[][]需要求一个区间最小值,我们尝试用线段树维护每一层的这个值。
枚举j,考虑每一层i。
我们设st[i],ed[i]分别表示在i左右距离i最远的st[i],ed[i]建基站依旧可以覆盖到i,假设我们已经求完了f[i][j]要求f[i+1][j],考虑那些恰可以被i覆盖到而不能被i+1覆盖到的,即满足ed[x]=i的点,将[1..st[x]-1]区间内的线段树值都加w[x],意为前一个基站k位于[1..st[x]-1]那么点x因不会被覆盖到需要做出赔偿。求f[i]的时候查询区间[1..i-1]内线段树值的最小即可。
其中st[i],ed[i]可以用二分法求。
线段树提供区间操作区间查询的操作。
总的时间复杂度为O(nmlogn)
辣鸡线段树,毁我青春(连个线段树都不会写了T^T
【代码】
#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; typedef long long ll;
const int N = 1e5+;
const int inf = 1e9; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} int n,K; ll f[N];
ll d[N],c[N],s[N],w[N],st[N],ed[N];
vector<ll> ep[N]; struct Tnode {
int l,r; ll v,tag;
}T[N<<]; void pushdown(int u)
{
if(T[u].l==T[u].r||(!T[u].tag)) return ;
ll& t=T[u].tag;
T[u<<].v+=t,T[u<<].tag+=t;
T[u<<|].v+=t,T[u<<|].tag+=t;
t=;
}
void maintain(int u)
{
T[u].v=min(T[u<<].v,T[u<<|].v);
}
void build(int u,int l,int r)
{
T[u].l=l,T[u].r=r;
T[u].tag=;
if(l==r) T[u].v=f[l];
else {
int mid=l+r>>;
build(u<<,l,mid);
build(u<<|,mid+,r);
maintain(u);
}
}
void Add(int u,int L,int R,ll x)
{
if(L>R) return ; //处理 L>R
pushdown(u);
if(L<=T[u].l&&T[u].r<=R)
T[u].v+=x,T[u].tag+=x;
else {
int mid=T[u].l+T[u].r>>;
if(L<=mid) Add(u<<,L,R,x);
if(mid<R) Add(u<<|,L,R,x);
maintain(u);
}
}
ll query(int u,int L,int R)
{
if(L>R) return ;
pushdown(u);
if(L<=T[u].l&&T[u].r<=R) return T[u].v;
else {
int mid=T[u].l+T[u].r>>; ll ans=inf;
if(L<=mid) ans=min(ans,query(u<<,L,R));
if(mid<R) ans=min(ans,query(u<<|,L,R));
return ans;
}
} //lower_bound定义为找到第一个不小于v的数的指针
void init()
{
n=read(),K=read();
FOR(i,,n) d[i]=read();
FOR(i,,n) c[i]=read();
FOR(i,,n) s[i]=read();
FOR(i,,n) w[i]=read();
n++,K++;
d[n]=inf; w[n]=inf;
FOR(i,,n) {
int l=d[i]-s[i],r=d[i]+s[i];
l=lower_bound(d+,d+n+,l)-d;
r=lower_bound(d+,d+n+,r)-d;
if(d[i]+s[i]<d[r]) r--;
st[i]=l,ed[i]=r;
ep[ed[i]].push_back(i);
}
}
ll dp()
{
ll ans,tmp=;
FOR(i,,n) {
f[i]=tmp+c[i];
FOR(j,,(int)ep[i].size()-)
tmp+=w[ep[i][j]];
}
ans=f[n];
FOR(j,,K) {
build(,,n);
FOR(i,,n) {
f[i]=query(,,i-)+c[i];
FOR(k,,(int)ep[i].size()-) {
int x=ep[i][k];
Add(,,st[x]-,w[x]);
}
}
ans=min(ans,f[n]);
}
return ans;
} int main()
{
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
init();
printf("%lld",dp());
return ;
}
bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)的更多相关文章
- BZOJ 1835 [ZJOI2010]base 基站选址:线段树优化dp
传送门 题意 有 $ n $ 个村庄在一排直线上,现在要建造不超过 $ K $ 个通讯基站,基站只能造在村庄处. 第 $ i $ 个村庄距离第 $ 1 $ 个村庄的距离为 $ D_i $ .在此建造基 ...
- BZOJ 1835: [ZJOI2010]base 基站选址 [序列DP 线段树]
1835: [ZJOI2010]base 基站选址 题目描述 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立 ...
- BZOJ 1835: [ZJOI2010]base 基站选址(DP,线段树)
可以很容易的写出dp方程: F[i][j]=min(F[l][j-1]+w[l][i])+c[i] (w[i][j]是从l+1到i-1这些点p里,所有满足d[p]+s[p]<d[i] & ...
- BZOJ1835: [ZJOI2010]base 基站选址【线段树优化DP】
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- 2018.11.06 bzoj1835: [ZJOI2010]base 基站选址(线段树优化dp)
传送门 二分出每个点不需要付www贡献的范围,然后可以推出转移式子: f[i][j]=f[i−1][k]+value(k+1,j)+c[i]f[i][j]=f[i-1][k]+value(k+1,j) ...
- bzoj 1835: [ZJOI2010]base 基站选址
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- bzoj[1835][ZJOI2010]base 基地选址
bzoj[1835][ZJOI2010]base 基地选址 标签: 线段树 DP 题目链接 题解 这个暴力DP的话应该很容易看出来. dp[i][j]表示造了i个通讯站,并且j是第i个的最小费用. \ ...
- bzoj 1835 base 基站选址 - 动态规划 - 线段树
题目传送门 需要高级权限的传送门 题目大意 有$n$个村庄坐落在一条直线上,第$i \ \ \ (i>1)$个村庄距离第$1$个村庄的距离为$D_i$.需要在这些村庄中建立不超过$K$个通讯基站 ...
- BZOJ 1835 基站选址(DP+线段树)
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream& ...
随机推荐
- bzoj 1228: [SDOI2009]E&D 阿达马矩阵
1228: [SDOI2009]E&D Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 448 Solved: 240[Submit][Sta ...
- 用css制作三角形
用css制作三角形,主要是利用css元素给“盒模型”设置边框得到的. 上图,上边框和做边框,以及上边框和右边框的交合处,浏览器会按照直角的二分之一处绘制交合线.这是“盒模型”有宽和高时候的效果.我们假 ...
- Flume学习——BasicChannelSemantics
public class MemoryChannel extends BasicChannelSemantics public abstract class BasicChannelSemantics ...
- Unix/Linux下如何使用Vi编辑器
vi 的工作模式 Vi 在初始启动后首先进入编辑模式,这时用户可以利用一些预先定义的按键来移动光标.删除文字. 复制或粘贴文字等.这些按键均是普通的字符,例如 l 是向右移动光标,相当于向右箭头键,k ...
- MVC开发过程中的疑难杂症
MVC使用客户端验证 <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type=& ...
- AIDL与stub
Stub翻译成中文是存根的意思,注意Stub对象是在被调用端进程,也就是服务端进程,至此,服务端aidl服务端得编码完成了. stub是为了方便client,service交互而生成出来的代码.A ...
- FastScroll(2)不分组的listview 打开fastscroll的分组提示功能
本文只让fastscroll具有提示分组功能,但listview并不显示分组,如果想让分组的listview显示fastscroll,看下篇. 1,在listview中打开fastscroll 2,自 ...
- int21 h
表:DOS系统功能调INT 21H AH 功能 调用参数 返回参数 00 程序终止(同INT 20H) CS=程序段前缀 01 键盘输入并回显 AL=输入字符 02 显示输出 DL=输出字符 03 异 ...
- MSSQL复制功能实现与Oracle数据库同步
1.分别建立链接对数据库进行操作,SQLServer可以用ADO.NET,操作Oracle可以用OLEDB或者用System.Data.OracleClient(需要添加引用才能用) 这种方案的优点就 ...
- jQgrid问题总结
最近一段时间一直在使用jqgrid这个免费的插件,网上的资料也比较多.比较全,但是这里还是整理几个自己在开发过程中遇到的小问题. 1.自动换行 一行数据过多需要自动根据内容换行时,如果遇到在表格中的汉 ...