Luogu P2605 [ZJOI2010]基站选址

题链

分析

考虑最基本的DP,设\(f[i][j]\)表示前\(i\)个,建\(j\)个基站,其中第\(j\)个基站在\(i\)上,只考虑\(1->i\)的最小答案

\[ f[i][j]=min(f[k][j-1]+cost(k,i))+co[i],k<i \]

其中\(cost(k,i)\)表示\([k,i]\)\(k\)\(i\)上有基站的补偿费
可以建一个虚点\(n+1\),则最后答案为\(min{f[n+1][k],k \in [1,m+1]}\)
考虑优化\(cost\)
每个点能被覆盖的基站的范围是\([d[i]-s[i],d[i]+s[i]]\),只与i有关
发现当一个节点在右边\(i\)不被覆盖,则也不会被\(i+1,i+2,...\)覆盖
所以可以预处理出每个节点最右边能使其被覆盖的节点,记作\(R[i]\),同时求出每个节点最左边的节点\(L[i]\);
当遍历到\(R[i]\)时,将\([0,L[i]-1]\)\(f\)加上\(w[i]\)
用线段树维护即可
注意:维护初始值需要维护建立一个基站的情况,以保证性质不被1破坏

#include<bits/stdc++.h>
using namespace std;

const int N=2e5+5;
int n,m,d[N],co[N],c[N],t[N],f[N],w[N],s[N],L[N],R[N];
vector<int>V[N];

inline int low(int l,int r,int x) {
	int mid,ret=l;
	while(l<=r) {
		int mid=l+r>>1;
		if(x<=d[mid]) ret=mid,r=mid-1;
			else l=mid+1;
	}
	return ret;
}

inline int upp(int l,int r,int x) {
	int mid,ret=r;
	while(l<=r) {
		int mid=l+r>>1;
		if(x>=d[mid]) ret=mid,l=mid+1;
			else r=mid-1;
	}
	return ret;
}

inline void up(int p) {
	c[p]=min(c[p<<1],c[p<<1|1]);
}
void bld(int p,int l,int r) {
	c[p]=t[p]=0;
	if(l==r) {
		c[p]=f[l]; return;
	}
	int mid=l+r>>1;
	bld(p<<1,l,mid),bld(p<<1|1,mid+1,r);
	up(p);
}

inline void down(int p,int l,int r,int mid) {
if(t[p]) {
	if(l<=mid) c[p<<1]+=t[p],t[p<<1]+=t[p];
	if(mid<r) c[p<<1|1]+=t[p],t[p<<1|1]+=t[p];
	t[p]=0;
}
}
int ask(int p,int l,int r,int x,int y) {
	if(x>y) return 0;
	if(l==x&&r==y) {
		return c[p];
	}
	int mid=l+r>>1;
	down(p,l,r,mid);
	if(y<=mid) return ask(p<<1,l,mid,x,y);
	if(x>mid) return ask(p<<1|1,mid+1,r,x,y);
	return min(ask(p<<1,l,mid,x,mid),ask(p<<1|1,mid+1,r,mid+1,y));
}

void add(int p,int l,int r,int x,int y,int k) {
	if(l==x&&r==y) {
		c[p]+=k; t[p]+=k; return;
	}
	int mid=l+r>>1;
	down(p,l,r,mid);
	if(y<=mid) add(p<<1,l,mid,x,y,k);
		else if(x>mid) add(p<<1|1,mid+1,r,x,y,k);
			else {
				add(p<<1,l,mid,x,mid,k);
				add(p<<1|1,mid+1,r,mid+1,y,k);
			}
	up(p);
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=2;i<=n;i++) scanf("%d",&d[i]);
	for(int i=1;i<=n;i++) scanf("%d",&co[i]);
	for(int i=1;i<=n;i++) scanf("%d",&s[i]);
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	n++,m++; d[n]=2e9;
	for(int i=1;i<=n;i++) {
		L[i]=low(1,i,d[i]-s[i]);
		R[i]=upp(i,n,d[i]+s[i]);
		V[R[i]].push_back(i);
	}
	int t=0;
	for(int i=1;i<=n;i++) {
		f[i]=t+co[i];
		for(auto v:V[i])t+=w[v];
	}
	int ans=f[n];
	for(int j=2;j<=m;j++) {
		bld(1,0,n);
		for(int i=j;i<=n;i++) {
			f[i]=ask(1,0,n,j-1,i-1)+co[i];
			for(auto v:V[i]) {
				add(1,0,n,0,L[v]-1,w[v]);
			}
		}
		ans=min(ans,f[n]);
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2021-02-25 09:13  wwwsfff  阅读(72)  评论(0)    收藏  举报