bzoj 1835 base 基站选址 - 动态规划 - 线段树
Posted yyf0309
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(nklog n)$
Code
1 /** 2 * bzoj 3 * Problem#1835 4 * Accepted 5 * Time: 2468ms 6 * Memory: 11300k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 #include <queue> 13 using namespace std; 14 typedef bool boolean; 15 #define ll long long 16 17 const signed int inf = (signed) (~0u >> 2); 18 const int N = 2e4 + 5, Kmx = 105; 19 20 typedef class Segment { 21 public: 22 int l, r, cost; 23 24 boolean operator < (Segment s) const { 25 return r < s.r; 26 } 27 }Segment; 28 29 typedef class SegTreeNode { 30 public: 31 int val, tg; 32 SegTreeNode *l, *r; 33 34 void pushUp() { 35 val = (l->val < r->val) ? (l->val) : (r->val); 36 } 37 38 void pushDown() { 39 l->val += tg, l->tg += tg; 40 r->val += tg, r->tg += tg; 41 tg = 0; 42 } 43 }SegTreeNode; 44 45 SegTreeNode pool[N << 2]; 46 SegTreeNode *top; 47 48 SegTreeNode* newnode() { 49 top->val = inf, top->tg = 0; 50 top->l = top->r = NULL; 51 return top++; 52 } 53 54 typedef class SegTree { 55 public: 56 int n; 57 SegTreeNode* rt; 58 59 SegTree() { } 60 SegTree(int n):n(n) { 61 top = pool; 62 build(rt, 1, n); 63 } 64 65 void build(SegTreeNode*& p, int l, int r) { 66 p = newnode(); 67 if (l == r) 68 return; 69 int mid = (l + r) >> 1; 70 build(p->l, l, mid); 71 build(p->r, mid + 1, r); 72 } 73 74 void update(SegTreeNode* p, int l, int r, int ql, int qr, int val) { 75 if (ql == l && r == qr) { 76 p->val += val; 77 p->tg += val; 78 return; 79 } 80 if (p->tg) 81 p->pushDown(); 82 int mid = (l + r) >> 1; 83 if (qr <= mid) 84 update(p->l, l, mid, ql, qr, val); 85 else if (ql > mid) 86 update(p->r, mid + 1, r, ql, qr, val); 87 else { 88 update(p->l, l, mid, ql, mid, val); 89 update(p->r, mid + 1, r, mid + 1, qr, val); 90 } 91 p->pushUp(); 92 } 93 94 void update(SegTreeNode* p, int l, int r, int idx, int val) { 95 if (l == r) { 96 p->val = val; 97 return; 98 } 99 if (p->tg) 100 p->pushDown(); 101 int mid = (l + r) >> 1; 102 if (idx <= mid) 103 update(p->l, l, mid, idx, val); 104 else 105 update(p->r, mid + 1, r, idx, val); 106 p->pushUp(); 107 } 108 109 int query() { 110 return rt->val; 111 } 112 113 void update(int l, int r, int val) { 114 if (l > r) 115 return; 116 update(rt, 1, n, l, r, val); 117 } 118 119 void update(int p, int val) { 120 update(rt, 1, n, p, val); 121 } 122 }SegTree; 123 124 int n, K, tp = 0; 125 int dist[N], cost[N], rang[N]; 126 int comp[N]; 127 int f[Kmx][N]; 128 Segment sgs[N]; 129 SegTree st; 130 131 inline void init() { 132 scanf("%d%d", &n, &K); 133 dist[1] = 0; 134 for (int i = 2; i <= n; i++) 135 scanf("%d", dist + i); 136 for (int i = 1; i <= n; i++) 137 scanf("%d", cost + i); 138 for (int i = 1; i <= n; i++) 139 scanf("%d", rang + i); 140 for (int i = 1; i <= n; i++) 141 scanf("%d", comp + i); 142 } 143 144 int res = 0; 145 inline void solve() { 146 for (int i = 1; i <= n; i++) { 147 int l = dist[i] - rang[i], r = dist[i] + rang[i]; 148 sgs[i].l = lower_bound(dist + 1, dist + i + 1, l) - dist; 149 sgs[i].r = upper_bound(dist + i, dist + n + 1, r) - dist - 1; 150 sgs[i].cost = comp[i]; 151 } 152 153 sort(sgs + 1, sgs + n + 1); 154 155 for (int i = 1; i <= n; i++) 156 res += comp[i]; 157 if (!K) { 158 printf("%d", res); 159 return; 160 } 161 162 int costs = 0; 163 Segment* p = sgs + 1, *ped = sgs + n + 1; 164 for (int i = 1; i <= n; i++) { 165 f[1][i] = costs + cost[i]; 166 while (p != ped && p->r <= i) 167 costs += p->cost, p++; 168 } 169 170 for (int k = 1; k <= K; k++) { 171 st = SegTree(n); 172 p = sgs + 1; 173 for (int i = 1; i <= n; i++) { 174 f[k + 1][i] = st.query() + cost[i]; 175 while (p != ped && p->r <= i) 176 st.update(1, p->l - 1, p->cost), p++; 177 st.update(i, f[k][i]); 178 } 179 res = min(res, st.query()); 180 } 181 printf("%d", res); 182 } 183 184 int main() { 185 init(); 186 solve(); 187 return 0; 188 }
以上是关于bzoj 1835 base 基站选址 - 动态规划 - 线段树的主要内容,如果未能解决你的问题,请参考以下文章