日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[ZJOI2010] 基站选址(线段树优化dp)

發布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [ZJOI2010] 基站选址(线段树优化dp) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

problem

luogu-P2605

solution

首先,肯定都能想到最暴力的 dpdpdp

dpi,j:idp_{i,j}:idpi,j?:i 個村莊為止一共選了 jjj 個基站,且第 iii 個村莊一定建立基站的最小費用。

通過我們的定義可知第 nnn 個村莊一定被選,實際上未必。

所以我們可以建立第 n+1n+1n+1 個虛擬村莊,并要求改為建立 m+1m+1m+1 個基站。

設置信息:建立花費 c=0c=0c=0,賠償花費 w=∞w=\inftyw=,距離 d=∞d=\inftyd=。這樣就不會被其余村莊覆蓋到也不會產生新花費而且一定建設。

邊界我們設計好了,就看狀態轉移方程。

dpi,j=ci+min?{dpk,j?1+pay(k,i)}k<idp_{i,j}=c_i+\min\Big\{dp_{k,j-1}+pay(k,i)\Big\}\quad k<idpi,j?=ci?+min{dpk,j?1?+pay(k,i)}k<i

注意到第二維 jjj 是可以滾動的,所以本質上是一維的 dpdpdp 轉移 dpi=ci+min?k<i{dpk+pay(k,i)}dp_{i}=c_i+\min_{k<i}\Big\{dp_{k}+pay(k,i)\Big\}dpi?=ci?+mink<i?{dpk?+pay(k,i)}

pay(k,i):pay(k,i):pay(k,i): 相鄰兩個基站選址在 kkkiii 村莊,這中間未被覆蓋到的村莊一共支付的補償費。

這其實很好計算。

因為距離 ddd 是遞增的,我們完全可以用 lower_bound() 找到每個村莊能被覆蓋到的最遠左右村莊。不妨記為 sti/edist_i/ed_isti?/edi?

[sti,edi][st_i,ed_i][sti?,edi?] 中有一個村莊建立了基站,那么 iii 村莊就可以被覆蓋到,不需要支付補償費。

通常遇到這種區間產生花費的,我們會選擇前綴和優化,然后分離 i,ki,ki,k 各自的貢獻,把只有 kkk 產生的貢獻揉成一坨扔到線段樹上,最小值查詢,但自己想想這里的區間與通常情況的是不一樣的。

通常情況的表述應為**“能覆蓋 sis_isi? 范圍內的所有基站”,而不是此題的“被覆蓋”**。

這里我們轉化一下。

再看一遍一維 dpdpdp 的轉移,這次從 dpkdp_kdpk? 這里入手。

唯一給的限制是 k<ik<ik<i,所以 kkk 的取值是一段區間。

不難想到用線段樹維護,把 dpkdp_kdpk? 當成節點權值,然后查詢區間最小值。

如果我們線段樹查出來的 k<stxk<st_xk<stx?,那么就需要支付 wxw_xwx?

而我們順次考慮到村莊 i,stx≤i≤edxi,st_x\le i\le ed_xi,stx?iedx? 的時候,因為 iii 必建設基站,所以 xxx 村莊就會被覆蓋。

于是我們想到將這樣的 xxx 村莊掛到 edxed_xedx? 上面去,可能多個 edxed_xedx? 相同,用前向星/vector\text{vector}vector 存即可。

iii 考慮到 edxed_xedx?,考慮完后,i←edx+1i\leftarrow ed_x+1iedx?+1,我們就要給線段樹上 [1,stx)[1,st_x)[1,stx?) 這些村莊加上 wxw_xwx? 的花費。

就是個線段樹區間加操作。

答案就是每一輪的 dpn+1dp_{n+1}dpn+1? 取最小值。

就沒了。時間復雜度,O(nmlog?n)O(nm\log n)O(nmlogn),因為每個 xxx 只會掛在一個村莊下,遍歷到某個村莊就把掛著的所有 xxx 的貢獻一股腦往線段樹上加,均攤下來是 O(1)O(1)O(1) 的。

注意: 最開始的,只建設一個基站的情況要特殊初始化 dpdpdp,后面才能以 j?1j-1j?1 個基站的 dpidp_idpi? 建樹。

code

#include <bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define int long long #define maxn 20005 int n, k; int d[maxn], c[maxn], s[maxn], w[maxn], st[maxn], ed[maxn], dp[maxn]; vector < int > G[maxn];namespace SGT {#define lson now << 1#define rson now << 1 | 1#define mid (l + r >> 1)struct node { int tag, val; }t[maxn << 2];void pushdown( int now ) {if( ! t[now].tag ) return;t[lson].tag += t[now].tag;t[lson].val += t[now].tag;t[rson].tag += t[now].tag;t[rson].val += t[now].tag;t[now].tag = 0;}void build( int now, int l, int r ) {t[now].tag = 0;if( l == r ) { t[now].val = dp[l]; return; }build( lson, l, mid );build( rson, mid + 1, r );t[now].val = min( t[lson].val, t[rson].val );}void modify( int now, int l, int r, int L, int R, int v ) {if( R < l or r < L ) return;if( L <= l and r <= R ) { t[now].val += v, t[now].tag += v; return; }pushdown( now );modify( lson, l, mid, L, R, v );modify( rson, mid + 1, r, L, R, v );t[now].val = min( t[lson].val, t[rson].val );}int query( int now, int l, int r, int L, int R ) {if( r < L or R < l ) return inf;if( L <= l and r <= R ) return t[now].val;pushdown( now );return min( query( lson, l, mid, L, R ), query( rson, mid + 1, r, L, R ) );} }signed main() {scanf( "%lld %lld", &n, &k );for( int i = 2;i <= n;i ++ ) scanf( "%lld", &d[i] );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &c[i] );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &s[i] );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &w[i] );++ n, ++ k, w[n] = d[n] = inf;for( int i = 1;i <= n;i ++ ) {ed[i] = upper_bound( d + 1, d + n + 1, d[i] + s[i] ) - d - 1;st[i] = lower_bound( d + 1, d + n + 1, d[i] - s[i] ) - d;G[ed[i]].push_back( i );}for( int i = 1, now = 0;i <= n;i ++ ) {dp[i] = now + c[i];for( int j : G[i] ) now += w[j];}int ans = dp[n];for( int j = 2;j <= k;j ++ ) {SGT :: build( 1, 1, n );for( int i = 1;i <= n;i ++ ) {dp[i] = c[i] + SGT :: query( 1, 1, n, 1, i - 1 );for( int p : G[i] ) SGT :: modify( 1, 1, n, 1, st[p] - 1, w[p] );}ans = min( ans, dp[n] );}printf( "%lld\n", ans );return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的[ZJOI2010] 基站选址(线段树优化dp)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。