BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)

题目大意:略 洛谷题面传送门 BZOJ题面传送门

注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了

定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一个基站建在了i处,最小的总花费

$f[i][k]=min(f[j][k]+calc(j,i))\;calc(j,i)$表示$i$和$j$之间,无法被覆盖的点,需要付的补偿总和

考虑如何求出$calc(j,i)$

定义$st_{i}$,$ed_{i}$表示第$i$个村庄能覆盖的最左端点和最右端点

即$st_{i}$到$ed_{i}$之间只要有一个村庄有基站,那么村庄i就不需要被补偿

可以用二分查找实现

把相同$ed_{i}$的村庄编号记录在$ed_{i}$这个位置

$DP$时,我们从左往右遍历要建基站的位置$x$,如果有一个村庄$i$的$ed_{i}<$当前位置$x$,那么如果$x$的决策如果选在了$[1,st_{i}-1]$,即上一个基站建在了$[1,st_{i}-1]$,那么村庄$i$需要被补偿,区间修改,用线段树实现

而转移就是查询区间最小值,同样用线段树实现即可

细节略多

 

  1 #include <vector>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 20010
  6 #define K1 105
  7 #define ll long long
  8 #define dd double
  9 #define inf 0x3f3f3f3f3f3f3f3fll
 10 using namespace std;
 11 
 12 int gint()
 13 {
 14     int ret=0,fh=1;char c=getchar();
 15     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 16     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 17     return ret*fh;
 18 }
 19 
 20 struct SEG{
 21 ll mi[N1<<2],tag[N1<<2];
 22 inline void pushup(int rt){ mi[rt]=min(mi[rt<<1],mi[rt<<1|1]); }
 23 inline void pushdown(int rt)
 24 {
 25     if(!tag[rt]) return;
 26     mi[rt<<1]+=tag[rt]; mi[rt<<1|1]+=tag[rt];
 27     tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt];
 28     tag[rt]=0;
 29 }
 30 void build(ll *f,int l,int r,int rt)
 31 {
 32     tag[rt]=0;
 33     if(l==r){ mi[rt]=f[l]; return; } 
 34     int mid=(l+r)>>1;
 35     build(f,l,mid,rt<<1);
 36     build(f,mid+1,r,rt<<1|1);
 37     pushup(rt);
 38 }
 39 void update(int L,int R,int l,int r,int rt,ll w)
 40 {
 41     if(L<=l&&r<=R){ mi[rt]+=w; tag[rt]+=w; return; }
 42     int mid=(l+r)>>1; pushdown(rt);
 43     if(L<=mid) update(L,R,l,mid,rt<<1,w);
 44     if(R>mid) update(L,R,mid+1,r,rt<<1|1,w);
 45     pushup(rt);
 46 }
 47 ll query(int L,int R,int l,int r,int rt)
 48 {
 49     if(L<=l&&r<=R) return mi[rt];
 50     int mid=(l+r)>>1; ll ans=inf; pushdown(rt); 
 51     if(L<=mid) ans=min(ans,query(L,R,l,mid,rt<<1));
 52     if(R>mid) ans=min(ans,query(L,R,mid+1,r,rt<<1|1));
 53     return ans;
 54 }
 55 }s;
 56 
 57 vector<int>id[N1];
 58 int n,K;
 59 int d[N1],c[N1],p[N1],w[N1],st[N1],ed[N1];
 60 ll f[N1];
 61 
 62 int main()
 63 {
 64     scanf("%d%d",&n,&K);
 65     int i,j,k,l,r,x,mid; ll ans=inf;
 66     for(i=2;i<=n;i++) d[i]=gint();
 67     for(i=1;i<=n;i++) c[i]=gint();
 68     for(i=1;i<=n;i++) p[i]=gint();
 69     for(i=1;i<=n;i++) w[i]=gint();
 70     for(i=1;i<=n;i++)
 71     {
 72         l=1,r=i,st[i]=i;
 73         while(l<=r)
 74         {
 75             mid=(l+r)>>1;
 76             if(d[mid]>=d[i]-p[i]) st[i]=mid,r=mid-1;
 77             else l=mid+1;
 78         }
 79         l=i,r=n,ed[i]=i;
 80         while(l<=r)
 81         {
 82             mid=(l+r)>>1;
 83             if(d[mid]<=d[i]+p[i]) ed[i]=mid,l=mid+1;
 84             else r=mid-1;
 85         }
 86         id[ed[i]].push_back(i);
 87     }
 88     memset(s.mi,0x3f,sizeof(s.mi));
 89     s.update(0,0,0,n,1,-(inf));
 90     for(k=1;k<=K;k++)
 91     {
 92         for(i=1;i<=n+1;i++)
 93         {
 94             f[i]=s.query(0,i-1,0,n,1)+c[i];
 95             for(j=0;j<id[i].size();j++)
 96             {
 97                 x=id[i][j];
 98                 s.update(0,st[x]-1,0,n,1,w[x]);
 99             }
100         }
101         ans=min(ans,f[n+1]);
102         s.build(f,0,n,1);
103     }
104     for(i=1;i<=n;i++)
105     {
106         for(j=0;j<id[i].size();j++)
107         {
108             x=id[i][j];
109             s.update(0,st[x]-1,0,n,1,w[x]);
110         }
111     }
112     ans=min(ans,s.query(0,n,0,n,1));
113     printf("%lld\n",ans);
114     return 0;
115 }

 

posted @ 2019-01-13 15:42  guapisolo  阅读(190)  评论(0编辑  收藏  举报