bzoj1835 [ZJOI2010]基站选址

Posted Sinogi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1835 [ZJOI2010]基站选址相关的知识,希望对你有一定的参考价值。

1835: [ZJOI2010]base 基站选址

Time Limit: 100 Sec  Memory Limit: 64 MB
Submit: 1648  Solved: 760
[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

 

以上是关于bzoj1835 [ZJOI2010]基站选址的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)

bzoj1835[ZJOI2010]base基站选址

BZOJ 1835 [ZJOI2010]base 基站选址

bzoj1835: [ZJOI2010]base 基站选址

[BZOJ1835][ZJOI2010]base 基站选址(DP+线段树)

BZOJ 1835 基站选址(DP+线段树)