1. 程式人生 > >BZOJ1835: [ZJOI2010]base 基站選址(線段樹優化Dp)

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

Description

有N個村莊坐落在一條直線上,第i(i>1)個村莊距離第1個村莊的距離為Di。需要在這些村莊中建立不超過K個通訊基站,在第i個村莊建立基站的費用為Ci。如果在距離第i個村莊不超過Si的範圍內建立了一個通訊基站,那麼就成它被覆蓋了。如果第i個村莊沒有被覆蓋,則需要向他們補償,費用為Wi。現在的問題是,選擇基站的位置,使得總費用最小。 輸入資料 (base.in) 輸入檔案的第一行包含兩個整數N,K,含義如上所述。 第二行包含N-1個整數,分別表示D2,D3,…,DN ,這N-1個數是遞增的。 第三行包含N個整數,表示C1,C2,…CN。 第四行包含N個整數,表示S1,S2,…,SN。 第五行包含N個整數,表示W1,W2,…,WN。

Input

輸出檔案中僅包含一個整數,表示最小的總費用。

Output

3 2 1 2 2 3 2 1 1 0 10 20 30

Sample Input

4

Sample Output

40%的資料中,N<=500;
100%的資料中,K<=N,K<=100,N<=20,000,Di<=1000000000,Ci<=10000,Si<=1000000000,Wi<=10000。

解題思路:

一道好題,不過我沒時間寫題解了,暫且咕在這裡。

程式碼:

  1 #include<cstdio>
  2 #include<vector>
  3
#include<cstring> 4 #include<algorithm> 5 #define lll spc<<1 6 #define rrr spc<<1|1 7 typedef long long lnt; 8 const int N=30010; 9 struct trnt{ 10 lnt lzt; 11 lnt minv; 12 }tr[N<<2],stt; 13 int n,k; 14 lnt w[N],s[N],d[N],c[N]; 15 int lp[N],rp[N];
16 lnt dp[N]; 17 std::vector<lnt>lim[N]; 18 void pushup(int spc) 19 { 20 tr[spc].minv=std::min(tr[lll].minv,tr[rrr].minv); 21 return ; 22 } 23 void add(int spc,lnt v) 24 { 25 tr[spc].minv+=v; 26 tr[spc].lzt+=v; 27 return ; 28 } 29 void pushdown(int spc) 30 { 31 if(tr[spc].lzt) 32 { 33 add(lll,tr[spc].lzt); 34 add(rrr,tr[spc].lzt); 35 tr[spc].lzt=0; 36 } 37 return ; 38 } 39 void build(int l,int r,int spc) 40 { 41 tr[spc]=stt; 42 if(l==r) 43 { 44 tr[spc].minv=dp[l]; 45 return ; 46 } 47 int mid=(l+r)>>1; 48 build(l,mid,lll); 49 build(mid+1,r,rrr); 50 pushup(spc); 51 return ; 52 } 53 void update(int l,int r,int ll,int rr,int spc,lnt v) 54 { 55 if(l>rr||ll>r) 56 return ; 57 if(ll<=l&&r<=rr) 58 { 59 add(spc,v); 60 return ; 61 } 62 int mid=(l+r)>>1; 63 pushdown(spc); 64 update(l,mid,ll,rr,lll,v); 65 update(mid+1,r,ll,rr,rrr,v); 66 pushup(spc); 67 return ; 68 } 69 lnt query(int l,int r,int ll,int rr,int spc) 70 { 71 if(l>rr||ll>r) 72 return 0x3f3f3f3f; 73 if(ll<=l&&r<=rr) 74 return tr[spc].minv; 75 int mid=(l+r)>>1; 76 pushdown(spc); 77 return std::min(query(l,mid,ll,rr,lll),query(mid+1,r,ll,rr,rrr)); 78 } 79 int main() 80 { 81 scanf("%d%d",&n,&k); 82 for(int i=2;i<=n;i++) 83 scanf("%lld",&d[i]); 84 for(int i=1;i<=n;i++) 85 scanf("%lld",&c[i]); 86 for(int i=1;i<=n;i++) 87 scanf("%lld",&s[i]); 88 for(int i=1;i<=n;i++) 89 scanf("%lld",&w[i]); 90 for(int i=1;i<=n;i++) 91 { 92 lp[i]=rp[i]=i; 93 int l=1,r=i-1; 94 while(l<=r) 95 { 96 int mid=(l+r)>>1; 97 if(d[i]-d[mid]<=s[i]) 98 { 99 r=mid-1; 100 lp[i]=mid; 101 }else 102 l=mid+1; 103 } 104 l=i+1,r=n; 105 while(l<=r) 106 { 107 int mid=(l+r)>>1; 108 if(d[mid]-d[i]<=s[i]) 109 { 110 l=mid+1; 111 rp[i]=mid; 112 }else 113 r=mid-1; 114 } 115 lim[rp[i]].push_back(i); 116 } 117 lnt sum=0; 118 for(int i=1;i<=n;i++) 119 { 120 dp[i]=c[i]+sum; 121 for(int j=0;j<lim[i].size();j++) 122 sum+=w[lim[i][j]]; 123 } 124 lnt ans=sum; 125 for(int i=1;i<=k;i++) 126 { 127 build(1,n,1); 128 for(int j=1;j<=n;j++) 129 { 130 dp[j]=query(1,n,1,j-1,1)+c[j]; 131 for(int o=0;o<lim[j].size();o++) 132 update(1,n,1,lp[lim[j][o]]-1,1,w[lim[j][o]]); 133 } 134 ans=std::min(ans,query(1,n,1,n,1)); 135 } 136 printf("%lld\n",ans); 137 return 0; 138 }