题目传送门

  需要高级权限的传送门

题目大意

  有$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 基站选址 - 动态规划 - 线段树的更多相关文章

  1. BZOJ 1835 [ZJOI2010]base 基站选址:线段树优化dp

    传送门 题意 有 $ n $ 个村庄在一排直线上,现在要建造不超过 $ K $ 个通讯基站,基站只能造在村庄处. 第 $ i $ 个村庄距离第 $ 1 $ 个村庄的距离为 $ D_i $ .在此建造基 ...

  2. BZOJ1835: [ZJOI2010]base 基站选址【线段树优化DP】

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

  3. 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) ...

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

    [BZOJ1835]基站选址(线段树) 题面 BZOJ 题解 考虑一个比较暴力的\(dp\) 设\(f[i][j]\)表示建了\(i\)个基站,最后一个的位置是\(j\)的最小代价 考虑如何转移\(f ...

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

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

  6. bzoj 1835: [ZJOI2010]基站选址

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

  7. 【洛谷2605】[ZJOI2010] 基站选址(线段树维护DP)

    点此看题面 大致题意: 有\(n\)个村庄,每个村庄有\(4\)个属性:\(D_i\)表示与村庄\(1\)的距离,\(C_i\)表示建立基站的费用,\(S_i\)表示能将其覆盖的建基站范围,\(W_i ...

  8. BZOJ 1835 基站选址(线段树优化DP)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1835 题意:有N个村庄坐落在一条直线上,第 i(i>1)个村庄距离第1个村庄的距离 ...

  9. BZOJ 1835 基站选址(DP+线段树)

    # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream& ...

随机推荐

  1. java可供判断某字符串是什么编码的一行代码

    System.out.println("中文"); System.out.println("中文".getBytes()); System.out.printl ...

  2. perl 递归删除目录和目录中的文件

    #!/usr/bin/perl use autodie; use utf8; use Encode qw(decode encode); sub del_dir{ my $path = shift @ ...

  3. hibernate09--连接查询

    创建实体类 package cn.bdqn.bean; import java.util.ArrayList; import java.util.Date; import java.util.List ...

  4. 五子棋棋盘布局 table和ul哪个好

    想要在页面布局以上棋盘,可以用ul li 布局,但却有明显的缺点: 1.两行两列:ul li 下面如果再放li 会出错,只能是放其他的,比如div. 或者放li *行*列: 但是这样有两个明显缺陷: ...

  5. win 10安装Linux虚拟机教程

    1.首先下载虚拟机 用的是VMware 官方下载地址:https://my.vmware.com/en/web/vmware/free#desktop_end_user_computing/vmwar ...

  6. 补充:ajax post 方式请求

    1. 什么是ajax Ajax: asynchronous  javascript  and  xml (异步js和xml) 其是可以与服务器进行(异步/同步)交互的技术之一. ajax的语言载体是j ...

  7. 让我对 docker swarm mode 的基本原理豁然开朗的几篇英文博文

    关于 docker swarm mode 的基本架构 How does it work? Docker! Part 1: Swarm general architecture 关于 Overlay N ...

  8. Unified Temporal and Spatial Calibration for Multi-Sensor Systems

    下载链接:点击 为了提高机器人状态估计的准确性和鲁棒性,越来越多的应用依赖于来自多个互补传感器的数据. 为了在传感器融合中获得最佳性能,这些不同的传感器必须在空间上和时间上相互对准.为此,已经开发了许 ...

  9. 17.1-uC/OS-III消息管理(两种消息队列)

    1.使用消息队列 消息队列函数: 函数名 功能 OSQCreate() 创建一个消息队列 OSQDel() 删除一个消息队列 OSQFlush() 清空一个消息队列 OSQPend() 任务等待消息 ...

  10. 线程 学习教程(一): Java中终止(销毁)线程的方法

    结束线程有以下三种方法:(1)设置退出标志,使线程正常退出,也就是当run()方法完成后线程终止 (2)使用interrupt()方法中断线程 (3)使用stop方法强行终止线程(不推荐使用,Thre ...