BZOJ 1835 [ZJOI2010]base 基站选址

题解:Dp+线段树维护所有决策

f[i][j]表示第j个基站建在第i个位置,i之前的村庄与建基站的总费用的最小值

以j为阶段

枚举i,维护所有决策f[x][j-1];

当一个村庄q不能被i覆盖了,那么在1~p之间建立基站的决策费用要+c

p为q左边第一个不能覆盖q的村庄

复杂度O( nklogn);

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=20009;
const int inf=1000000000;

int n,m;
int ans=inf;
int f[maxn][109];
int d[maxn];
int c[maxn];
int w[maxn];
int s[maxn];
int Bl[maxn],Br[maxn];
vector<int>Tr[maxn],Tl[maxn];

struct SegmentTree{
	int l,r,tag,mn;
}tree[maxn<<2];
inline void pushup(int now){
	tree[now].mn=min(tree[now<<1].mn,tree[now<<1|1].mn);
}
inline void pushdown(int now){
	if(tree[now].tag){
		tree[now<<1].tag+=tree[now].tag;
		tree[now<<1|1].tag+=tree[now].tag;
		tree[now<<1].mn+=tree[now].tag;
		tree[now<<1|1].mn+=tree[now].tag;
		tree[now].tag=0;
	}
}
void BuildTree(int now,int l,int r,int p){
	tree[now].l=l;tree[now].r=r;tree[now].tag=0;
	if(l==r){
		tree[now].mn=f[l][p];
		return;
	}
	int mid=(l+r)>>1;
	BuildTree(now<<1,l,mid,p);
	BuildTree(now<<1|1,mid+1,r,p);
	pushup(now);
}
void Updatasec(int now,int ll,int rr,int x){
	if(ll>rr)return;
	if(tree[now].l>=ll&&tree[now].r<=rr){
		tree[now].tag+=x;tree[now].mn+=x;return;
	}
	pushdown(now);
	int mid=(tree[now].l+tree[now].r)>>1;
	if(ll<=mid)Updatasec(now<<1,ll,rr,x);
	if(rr>mid)Updatasec(now<<1|1,ll,rr,x);
	pushup(now);
}

int Querymin(int now,int ll,int rr){
	if(tree[now].l>=ll&&tree[now].r<=rr){
		return tree[now].mn;
	}
	pushdown(now);
	int mid=(tree[now].l+tree[now].r)>>1;
	int ret=inf;
	if(ll<=mid)ret=min(ret,Querymin(now<<1,ll,rr));
	if(rr>mid)ret=min(ret,Querymin(now<<1|1,ll,rr));
	return ret;
}

int main(){
	scanf("%d%d",&n,&m);
	d[1]=0;
	for(int i=2;i<=n;++i)scanf("%d",&d[i]);
	for(int i=1;i<=n;++i)scanf("%d",&c[i]);
	for(int i=1;i<=n;++i)scanf("%d",&s[i]);
	for(int i=1;i<=n;++i)scanf("%d",&w[i]);
	for(int i=1;i<=n;++i){
		int p,tmp;
		tmp=d[i]+s[i];
		p=lower_bound(d+1,d+1+n,tmp)-d;
		if(tmp<=d[n]){
			if(d[p]!=tmp)--p;
			Tr[p].push_back(i);
			Br[i]=p;
		}else{
			Br[i]=-1;
		}
		
		tmp=d[i]-s[i];
		p=lower_bound(d+1,d+1+n,tmp)-d;
		if(tmp>=0){
			Tl[p].push_back(i);
			Bl[i]=p;
		}else{
			Bl[i]=-1;
		}
	}
	
//	for(int i=1;i<=n;++i){
//		cout<<Bl[i]<<' '<<Br[i]<<endl;
//	}
	for(int tmp=0,i=1;i<=n;++i){
//		cout<<"ASD"<<' '<<i<<' '<<tmp<<endl;
		f[i][1]=tmp+c[i];
		for(int j=0;j<Tr[i].size();++j){
			int x=Tr[i][j];
			tmp+=w[x];
//			cout<<"eaint "<<tmp<<endl;
		}
	}
	for(int j=2;j<=m;++j){
		BuildTree(1,1,n,j-1);
		for(int i=1;i<=j-1;++i)f[i][j]=inf;
		for(int i=j;i<=n;++i){
			f[i][j]=Querymin(1,1,i-1)+c[i];
			for(int k=0;k<Tr[i].size();++k){
				int x=Tr[i][k];
				if(Bl[x]>1)Updatasec(1,1,Bl[x]-1,w[x]);
			}
		}
	}
	
	for(int tmp=0,i=n;i>=1;--i){
		for(int j=1;j<=m;++j){
			ans=min(ans,f[i][j]+tmp);
		}
		for(int j=0;j<Tl[i].size();++j){
			int x=Tl[i][j];
			tmp+=w[x];
		}
	}
//	for(int j=1;j<=m;++j){
//		for(int i=1;i<=n;++i){
//			cout<<f[i][j]<<' ';
//		}
//		cout<<endl;
//	}
	cout<<ans<<endl;
	return 0;
}

  

posted @ 2018-02-20 12:28  ws_zzy  阅读(145)  评论(0编辑  收藏  举报