1. 程式人生 > >bzoj 1835 base 基站選址

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 }

相關推薦

bzoj 1835 base 基站選址

題目傳送門 題目大意   有$n$個村莊坐落在一條直線上,第$i \ \ \ (i>1)$個村莊距離第$1$個村莊的距離為$D_i$。需要在這些村莊中建立不超過$K$個通訊基站,在第$i$個村莊建立基站的費用為$C_i$。如果在距離第$i$個村莊不超過$S_i$的範圍內建立了一個通訊基站

BZOJ 1835 [ZJOI2010]基站選址 (線段樹優化DP)

geo har while 位置 如何 lse problem space getchar 題目大意:略 洛谷題面傳送門 BZOJ題面傳送門 註意題目的描述,是村莊在一個範圍內去覆蓋基站,而不是基站覆蓋村莊,別理解錯了 定義$f[i][k]$表示只考慮前i個村莊,一共建

BZOJ1835: [ZJOI2010]base 基站選址(線段樹優化Dp)

Description 有N個村莊坐落在一條直線上,第i(i>1)個村莊距離第1個村莊的距離為Di。需要在這些村莊中建立不超過K個通訊基站,在第i個村莊建立基站的費用為Ci。如果在距離第i個村莊不超過Si的範圍內建立了一個通訊基站,那麼就成它被覆蓋了。如果第i個村莊沒有被覆蓋,則需要向他們補償,

[ZJOI2010]基站選址

現在 for 遞增 最小花費 查詢 oid == 如果 優化 題目描述 有N個村莊坐落在一條直線上,第i(i>1)個村莊距離第1個村莊的距離為Di。需要在這些村莊中建立不超過K個通訊基站,在第i個村莊建立基站的費用為Ci。如果在距離第i個村莊不超過Si的範圍內建立了一

BZOJ 2426 [HAOI2010]工廠選址 【貪心】

如果 tar 兩個 input 加油! ret nbsp can 運行 BZOJ 2426 [HAOI2010]工廠選址 Description 某地區有m座煤礦,其中第i號礦每年產量為ai噸,現有火力發電廠一個,每年需用煤b噸,每年運行的固定費用(包括折舊費,不包括煤的

luogu2605 基站選址 (線段樹優化dp)

設f[i][j]表示在第i個村莊建第j個基站的花費 那麼有$f[i][j]=min\{f[k][j-1]+w[k,i]\}$,其中w[k,i]表示在k,i建基站,k,i中間的不能被滿足的村莊的賠償金之和 如果把每個村莊能被滿足的區間處理出來,記做$[l_i,r_i]$,那麼i,j不能滿足的村莊,就是$i&

[ZJOI2010]基站選址(線段樹優化dp)

坑待填。 \(Code\ Below:\) #include <bits/stdc++.h> #define lson (rt<<1) #define rson (rt<<1|1) using namespace std; const int maxn=20000+10

洛谷P2605 基站選址

open lap 不用 前綴 tor 其中 之前 超過 查詢 神TM毒瘤線段樹優化DP......新姿勢get。 題意:有n個村莊,在裏面選不多於k個建立基站。 建立基站要ci的費用。如果一個村莊方圓si內沒有基站,那麽又要支出wi的費用。求最小費用。 解:很顯然想到DP,

bzoj - 1007

namespace ans operator using str pac bitset top 技術 1 #include <algorithm> 2 #include <cstring> 3 #include <cstdio>

BZOJ 1411 ZJOI2009 硬幣遊戲

ret dea 遊戲 true 硬幣 air 技術 i++ include 遞推; 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using n

IOC Of Ninject Base On ASP.NET MVC

dex 準備工作 應用 new 引用 cti err art part 說在之前的話 IOC的概念相信大家比較熟悉了,習慣性稱之為依賴註入或控制反轉,園子裏對基於MVC平臺IOC設計模式已經相當多了,但大家都只知道應該怎麽應用一個IOC模式,比如Ninject, Unity

BZOJ 3122 SDOI2013 隨機數生成器

color false std ros == d+ eal eof close 公式就不推了.hzwer上的很清楚. 值得註意的一點是,如果最後答案成0,需要加上mod.否則400ms wa. 1 #include<cstdio> 2 #incl

BZOJ 4827 [Hnoi2017]禮物 ——FFT

最小 sharp scan con 禮物 struct swa 1.0 -i 題目上要求一個循環卷積的最小值,直接破環成鏈然後FFT就可以了。 然後考慮計算的式子,可以分成兩個部分分開計算。 前半部分FFT,後半部分掃一遍。 #include <map> #i

BZOJ 4569 [Scoi2016]萌萌噠 ——ST表 並查集

oid include long long amp else n) div 每一個 並查集 好題。 ST表又叫做稀疏表,這裏利用了他的性質。 顯然每一個條件可以分成n個條件,顯然過不了。 然後發現有許多狀態是重復的,首先考慮線段樹,沒什麽卵用。 然後ST表,可以每一層表示對

bzoj 1787: [Ahoi2008]Meet 緊急集合

點擊 緊急 ring input ahoi2008 nbsp mage swa problems 1787: [Ahoi2008]Meet 緊急集合 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 3016 Solve

BZOJ 2288 【POJ Challenge】生日禮物(貪心+優先隊列)

ace urn ons target challenge pri 最大 font return 【題目鏈接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2288 【題目大意】   給出一列數,求最多取m段

BZOJ 4884 [Lydsy2017年5月月賽]太空貓(單調DP)

return 畫面 int pac logs name 左右 ring size 【題目鏈接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4884 【題目大意】   太空貓(SpaceCat)是一款畫面精

BZOJ 4883 [Lydsy2017年5月月賽]棋盤上的守衛(最小生成環套樹森林)

print 我們 size -s nbsp long pan typedef 包含 【題目鏈接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4883 【題目大意】   在一個n*m的棋盤上要放置若幹個守衛

BZOJ——1602: [Usaco2008 Oct]牧場行走

com onclick {} scanf printf arch usaco2008 back sea http://www.lydsy.com/JudgeOnline/problem.php?id=1602 題目描述 N頭牛(2<=n<=1000)別人