bzoj 1835 base 基站选址 - 动态规划 - 线段树
题目传送门
题目大意
有$n$个村庄坐落在一条直线上,第$i \ \ \ (i>1)$个村庄距离第$1$个村庄的距离为$D_i$。需要在这些村庄中建立不超过$K$个通讯基站,在第$i$个村庄建立基站的费用为$C_i$。如果在距离第$i$个村庄不超过$S_i$的范围内建立了一个通讯基站,那么就成它被覆盖了。如果第$i$个村庄没有被覆盖,则需要向他们补偿,费用为$W_i$。现在的问题是,选择基站的位置,使得总费用最小。
三方dp是显然的,用$f_{i, j}$表示考虑前$i$个村庄,在第$i$个村庄建立基站的最小费用。
预处理一下,每个村庄距离不超过$S_i$的村庄区间。然后考虑用某个数据结构来维护转移。
将这些区间按照右端点排序,当当前考虑的$i$大于这个区间的右端点的时候,那么这个区间的左端点以前的状态的转移需要加上它的赔偿费用。
然后就做完了。时间复杂度$O(nk\log n)$
Code
/**
* bzoj
* Problem#1835
* Accepted
* Time: 2468ms
* Memory: 11300k
*/
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <queue>
using namespace std;
typedef bool boolean;
#define ll long long const signed int inf = (signed) (~0u >> );
const int N = 2e4 + , Kmx = ; typedef class Segment {
public:
int l, r, cost; boolean operator < (Segment s) const {
return r < s.r;
}
}Segment; typedef class SegTreeNode {
public:
int val, tg;
SegTreeNode *l, *r; void pushUp() {
val = (l->val < r->val) ? (l->val) : (r->val);
} void pushDown() {
l->val += tg, l->tg += tg;
r->val += tg, r->tg += tg;
tg = ;
}
}SegTreeNode; SegTreeNode pool[N << ];
SegTreeNode *top; SegTreeNode* newnode() {
top->val = inf, top->tg = ;
top->l = top->r = NULL;
return top++;
} typedef class SegTree {
public:
int n;
SegTreeNode* rt; SegTree() { }
SegTree(int n):n(n) {
top = pool;
build(rt, , n);
} void build(SegTreeNode*& p, int l, int r) {
p = newnode();
if (l == r)
return;
int mid = (l + r) >> ;
build(p->l, l, mid);
build(p->r, mid + , r);
} void update(SegTreeNode* p, int l, int r, int ql, int qr, int val) {
if (ql == l && r == qr) {
p->val += val;
p->tg += val;
return;
}
if (p->tg)
p->pushDown();
int mid = (l + r) >> ;
if (qr <= mid)
update(p->l, l, mid, ql, qr, val);
else if (ql > mid)
update(p->r, mid + , r, ql, qr, val);
else {
update(p->l, l, mid, ql, mid, val);
update(p->r, mid + , r, mid + , qr, val);
}
p->pushUp();
} void update(SegTreeNode* p, int l, int r, int idx, int val) {
if (l == r) {
p->val = val;
return;
}
if (p->tg)
p->pushDown();
int mid = (l + r) >> ;
if (idx <= mid)
update(p->l, l, mid, idx, val);
else
update(p->r, mid + , r, idx, val);
p->pushUp();
} int query() {
return rt->val;
} void update(int l, int r, int val) {
if (l > r)
return;
update(rt, , n, l, r, val);
} void update(int p, int val) {
update(rt, , n, p, val);
}
}SegTree; int n, K, tp = ;
int dist[N], cost[N], rang[N];
int comp[N];
int f[Kmx][N];
Segment sgs[N];
SegTree st; inline void init() {
scanf("%d%d", &n, &K);
dist[] = ;
for (int i = ; i <= n; i++)
scanf("%d", dist + i);
for (int i = ; i <= n; i++)
scanf("%d", cost + i);
for (int i = ; i <= n; i++)
scanf("%d", rang + i);
for (int i = ; i <= n; i++)
scanf("%d", comp + i);
} int res = ;
inline void solve() {
for (int i = ; i <= n; i++) {
int l = dist[i] - rang[i], r = dist[i] + rang[i];
sgs[i].l = lower_bound(dist + , dist + i + , l) - dist;
sgs[i].r = upper_bound(dist + i, dist + n + , r) - dist - ;
sgs[i].cost = comp[i];
} sort(sgs + , sgs + n + ); for (int i = ; i <= n; i++)
res += comp[i];
if (!K) {
printf("%d", res);
return;
} int costs = ;
Segment* p = sgs + , *ped = sgs + n + ;
for (int i = ; i <= n; i++) {
f[][i] = costs + cost[i];
while (p != ped && p->r <= i)
costs += p->cost, p++;
} for (int k = ; k <= K; k++) {
st = SegTree(n);
p = sgs + ;
for (int i = ; i <= n; i++) {
f[k + ][i] = st.query() + cost[i];
while (p != ped && p->r <= i)
st.update(, p->l - , p->cost), p++;
st.update(i, f[k][i]);
}
res = min(res, st.query());
}
printf("%d", res);
} int main() {
init();
solve();
return ;
}
bzoj 1835 base 基站选址 - 动态规划 - 线段树的更多相关文章
- BZOJ 1835 [ZJOI2010]base 基站选址:线段树优化dp
传送门 题意 有 $ n $ 个村庄在一排直线上,现在要建造不超过 $ K $ 个通讯基站,基站只能造在村庄处. 第 $ i $ 个村庄距离第 $ 1 $ 个村庄的距离为 $ 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) ...
- 【BZOJ1835】基站选址(线段树)
[BZOJ1835]基站选址(线段树) 题面 BZOJ 题解 考虑一个比较暴力的\(dp\) 设\(f[i][j]\)表示建了\(i\)个基站,最后一个的位置是\(j\)的最小代价 考虑如何转移\(f ...
- BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)
题目大意:略 洛谷题面传送门 BZOJ题面传送门 注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了 定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一 ...
- bzoj 1835: [ZJOI2010]基站选址
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- 【洛谷2605】[ZJOI2010] 基站选址(线段树维护DP)
点此看题面 大致题意: 有\(n\)个村庄,每个村庄有\(4\)个属性:\(D_i\)表示与村庄\(1\)的距离,\(C_i\)表示建立基站的费用,\(S_i\)表示能将其覆盖的建基站范围,\(W_i ...
- BZOJ 1835 基站选址(线段树优化DP)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1835 题意:有N个村庄坐落在一条直线上,第 i(i>1)个村庄距离第1个村庄的距离 ...
- BZOJ 1835 基站选址(DP+线段树)
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream& ...
随机推荐
- layui封装自定义模块
转自:https://lianghongbo.cn/blog/430585105a35948c layui是国人开发的一款非常简洁的UI框架,使用了模块化加载方式,因此在使用过程中我们难免需要添加自己 ...
- 每个JavaScript程序员都需要知道的5个数组方法
Array.forEach() .forEach() 方法能够方便的让你 遍历数组里的每个元素,你可以在回调函数里对每个元素进行操作..forEach()方法没有返回值,你不需要在回调函数里写retu ...
- Java应用之POI
POI的简介 Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. HSSF的概况 HSSF 是Horr ...
- Docker数据卷
1.volume操作命名:docker volume Usage: docker volume COMMAND Manage Docker volumes Options: --he ...
- tomcat配置内存
windows: Create a new script named as setenv.bat under TOMCAT_HOME/bin folder holding the following ...
- 【Python全栈-JavaScript】JavaScript的window.onload()与jQuery 的ready()的区别
JavaScript的window.onload()与jQuery 的ready()的区别 做web开发时常用Jquery中$(document).ready()和JavaScript中的window ...
- Spring Boot核心注解@SpringBootApplication
一.作用 @SpringBootApplication是一个组合注解,用于快捷配置启动类. 二.用法 可配置多个启动类,但启动时需选择以哪个类作为启动类来启动项目. 三.拆解 1.拆解 ...
- 安装mysql服务时提示“找不到msvcp140.dll”
没有安装VC++2015版运行库导致的(Microsoft Visual C++ 2015 Redistributable),下载地址https://www.microsoft.com/en-us/d ...
- SVProgressHUD提示框IOS
SVProgressHUD--比MBProgressHUD更好用的 iOS进度提示组件 项目里用到SVProgressHud,感觉背景颜色太丑,因为很久很久以前改过,就想在这个项目里也改下,但是时间过 ...
- .net 调用python 实例
如标题 ,python属于解释型语言,所以直接将python的文件copy到项目中 新建.net控制台应用程序,直接nuget IronPython 安装成功后 在项目内新建Sum文件夹,将py.p ...