BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)
注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了
定义$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 }