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

  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 }
posted @ 2018-10-15 08:15  阿波罗2003  阅读(431)  评论(0编辑  收藏  举报