bzoj1835 [ZJOI2010]base 基站选址 (线段树优化DP)

1835: [ZJOI2010]base 基站选址

Time Limit: 100 Sec  Memory Limit: 64 MB
Submit: 1649  Solved: 761
[Submit][Status][Discuss]

Description

有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。

Input

输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述。 第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。 第三行包含N个整数,表示C1,C2,…CN。 第四行包含N个整数,表示S1,S2,…,SN。 第五行包含N个整数,表示W1,W2,…,WN。

Output

输出文件中仅包含一个整数,表示最小的总费用。
 
 

用$dp[i][j]$表示第i个基站建在第j个村庄,转移方程为$dp[i][j]=min(dp[i-1][k]+cost[k][j])+C[j]$;

$cost[i][j]$表示在从$i$到$j$所需补偿;

可以预处理出左右两侧能覆盖村庄$i$的最远基站位置$L[i]$和$R[i]$;

当$j$变为$j+1$时,可能导致一部分原本能被覆盖到的村庄不再被覆盖;

因此从$j$移动到$j+1$时,对于所有$R[k]==j$的$k$,把区间$[1,L[k]-1]$加上$W[k]$;

区间最小值+区间加,可以用线段树维护;

枚举建造基站的个数,每次重建线段树,最终$ans=min(dp[i][j]+sum[j])$;

其中$sum[j]$表示最后一个基站建在$j$时,$j$右侧村庄所需补偿,计算方式与$cost$数组类似;

复杂度$O(knlogn)$;

AC GET☆DAZE

 
↓代码
  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<string>
  6 #include<vector>
  7 #include<bitset>
  8 #include<cmath>
  9 #include<queue>
 10 #include<ctime>
 11 #include<map>
 12 #include<set>
 13 #define N 20039
 14 #define ll long long
 15 #define inf 0x3f3f3f3f
 16 using namespace std;
 17 struct seg
 18 {
 19     int l,r,w,lazy;
 20 }tree[N<<3];
 21 int x[N],L[N],R[N],co[N],rw[N],sum[N],dp[N],ans,stp;
 22 bool use[N];
 23 vector<int> inl[N],inr[N];
 24 void pull_up(int k)
 25 {
 26     tree[k].w=min(tree[k<<1].w,tree[k<<1|1].w);
 27 }
 28 void push_down(int k)
 29 {
 30     if(tree[k].lazy)
 31     {
 32         tree[k<<1].w+=tree[k].lazy,tree[k<<1|1].w+=tree[k].lazy;
 33         tree[k<<1].lazy+=tree[k].lazy,tree[k<<1|1].lazy+=tree[k].lazy;
 34         tree[k].lazy=0;
 35     }
 36 }
 37 void build(int k,int l,int r)
 38 {
 39     tree[k].l=l,tree[k].r=r,tree[k].lazy=0;
 40     if(l==r)
 41     {
 42         tree[k].w=dp[l];
 43         return; 
 44     }
 45     int mid=l+r>>1;
 46     build(k<<1,l,mid);
 47     build(k<<1|1,mid+1,r);
 48     pull_up(k);
 49 }
 50 void update(int k,int l,int r,int v)
 51 {
 52     if(l>r)
 53     {
 54         return;
 55     }
 56     push_down(k);
 57     if(tree[k].l>=l && tree[k].r<=r)
 58     {
 59         tree[k].w+=v;
 60         tree[k].lazy+=v;
 61         return;
 62     }
 63     int mid=tree[k].l+tree[k].r>>1;
 64     if(mid>=r)
 65     {
 66         update(k<<1,l,r,v);
 67     }
 68     else if(mid<l)
 69     {
 70         update(k<<1|1,l,r,v);
 71     }
 72     else
 73     {
 74         update(k<<1,l,r,v),update(k<<1|1,l,r,v);
 75     }
 76     pull_up(k);
 77 }
 78 int query(int k,int l,int r)
 79 {
 80     if(l>r)
 81     {
 82         return 0;
 83     }
 84     push_down(k);
 85     if(tree[k].l>=l && tree[k].r<=r)
 86     {
 87         return tree[k].w;
 88     }
 89     int mid=tree[k].l+tree[k].r>>1;
 90     if(mid>=r)
 91     {
 92         return query(k<<1,l,r);
 93     }
 94     else if(mid<l)
 95     {
 96         return query(k<<1|1,l,r);
 97     }
 98     else
 99     {
100         return min(query(k<<1,l,r),query(k<<1|1,l,r));
101     }
102 }
103 int main()
104 {
105     int n,k,a,b,c;
106     scanf("%d%d",&n,&k);
107     for(a=2;a<=n;a++)
108     {
109         scanf("%d",&x[a]);
110     }
111     for(a=1;a<=n;a++)
112     {
113         scanf("%d",&co[a]);
114     }
115     for(a=1;a<=n;a++)
116     {
117         scanf("%d",&b);
118         L[a]=lower_bound(x+1,x+n+1,x[a]-b)-x;
119         R[a]=lower_bound(x+1,x+n+1,x[a]+b)-x;
120         if(x[R[a]]>x[a]+b)
121         {
122             R[a]--;
123         }
124         inl[L[a]].push_back(a);
125         inr[R[a]].push_back(a);
126     }
127     for(a=1;a<=n;a++)
128     {
129         scanf("%d",&rw[a]);
130         ans+=rw[a];
131     }
132     for(a=1,stp=ans;a<=n;a++)
133     {
134         for(b=0;b<inl[a].size();b++)
135         {
136             if(!use[inl[a][b]])
137             {
138                 stp-=rw[inl[a][b]];
139             }
140             use[inl[a][b]]=1;
141         }
142         sum[a]=stp;
143     }
144     for(a=1;a<=k;a++)
145     {
146         if(a==1)
147         {
148             for(b=1,stp=0;b<=n;b++)
149             {
150                 dp[b]=stp+co[b];
151                 for(c=0;c<inr[b].size();c++)
152                 {
153                     stp+=rw[inr[b][c]];
154                 }
155                 ans=min(ans,dp[b]+sum[b]);
156             }
157             continue;
158         }
159         build(1,1,n);
160         for(b=1;b<=n;b++)
161         {
162             dp[b]=query(1,1,b-1)+co[b];
163             for(c=0;c<inr[b].size();c++)
164             {
165                 update(1,1,L[inr[b][c]]-1,rw[inr[b][c]]);
166             }
167             ans=min(ans,dp[b]+sum[b]);
168         }
169     }
170     printf("%d",ans);
171     return 0;
172 }
bzoj1835

 

posted @ 2017-10-22 21:52  Sinogi  阅读(223)  评论(0编辑  收藏  举报