Connecting...

P2605 [ZJOI2010] 基站选址 sol

P2605 [ZJOI2010] 基站选址 - 洛谷

Observation 1

dp[i][k]: the former ith countrysides have k stations ,ith has one station

\[ dp[i][k]=\min dp[j][k-1]+cnt(j,i)+c[i] \]

inside:

int cnt(int l,int r){
	int res=0;
	for(int i=l+1;i<r;++i){
		if(d[i]-d[l]<=s[i]||d[r]-d[i]<=s[i])continue;
		res+=w[i];
	}return res;
}

and we can use node :n+1 to let the former nth node choose whether set station or not freely.

Observation 2

we can useL[i] R[i] to show the boundary which means ith contributes w[i] when all stations are out of it. \(\mathcal{O}(n\log n)\) is OK

then dp[i][j],when the j was fixed,we use \(\min\) dp[pos][j-1] to update dp[i][j],so we can use segment tree to maintenance.

concretely,we know which points contribute w_pos, so when we are dealing with i_th we add(1,L[i]-1,\(\sum\)w[pos]).then just query by \(\mathcal{O}(\log n)\)

talk is cheap show you the code

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N=5e4+10,K=1011,inf=INT_MAX;
int n,k,d[N],c[N],s[N],w[N];
int dp[N],L[N],R[N];
vector<int>ed[N]; 
struct SegTr{
	int l,r,val,tag;
}tr[N<<2];
/*
dp[i][k] the former ith countrysides have k stations ,ith has one station
dp[i][k]=\min dp[j][k-1]+cnt(j,i)+c[i]
*/ 
void init(){
	for(int i=1;i<=n+1;++i){
		L[i]=lower_bound(d+1,d+1+n+1,d[i]-s[i])-d;
		R[i]=upper_bound(d+1,d+1+n+1,d[i]+s[i])-d-1;
		ed[R[i]].push_back(i);
	}
}
void pushup(int x){
	tr[x].val=min(tr[x<<1].val,tr[x<<1|1].val);
} 
void pushdown(int x){
	tr[x<<1].val+=tr[x].tag;
	tr[x<<1|1].val+=tr[x].tag;
	tr[x<<1].tag+=tr[x].tag;
	tr[x<<1|1].tag+=tr[x].tag;
	tr[x].tag=0;
}
void build(int x,int l,int r){
	tr[x]={l,r,dp[l],0};
	if(l==r)return ;
	int mid=l+r>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	pushup(x); 
}
void add(int x,int l,int r,int k){
	if(l<=tr[x].l&&tr[x].r<=r){
		tr[x].tag+=k;
		tr[x].val+=k;
		return ;
	}
	pushdown(x);
	int mid=tr[x].l+tr[x].r>>1;
	if(l<=mid)add(x<<1,l,r,k);
	if(mid<r)add(x<<1|1,l,r,k);
	pushup(x);
}
int q(int x,int l,int r){
	if(l<=tr[x].l&&tr[x].r<=r)return tr[x].val;
	pushdown(x);
	int mid=tr[x].l+tr[x].r>>1,ans=inf;
	if(l<=mid)ans=min(ans,q(x<<1,l,r));
	if(mid<r)ans=min(ans,q(x<<1|1,l,r));
	return ans;
	
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>k;
	for(int i=2;i<=n;++i)cin>>d[i];
	for(int i=1;i<=n;++i)cin>>c[i];
	for(int i=1;i<=n;++i)cin>>s[i];
	for(int i=1;i<=n;++i)cin>>w[i];
	w[n+1]=inf,c[n+1]=0,s[n+1]=0,d[n+1]=inf;
	init(); 
	int res=0;
	for(int i=1;i<=n+1;++i) {
		dp[i]=res+c[i];
		for(auto v:ed[i])res+=w[v];
	}int ans=dp[n+1];
	for(int j=2;j<=k+1;++j){ 
		build(1,1,n+1);
		for(int i=1;i<=n+1;++i){
			dp[i]=q(1,1,i-1)+c[i];
			for(auto v:ed[i]) if(L[v]-1>=1)add(1,1,L[v]-1,w[v]);
		}
		ans=min(ans,dp[n+1]);
	}
	cout<<ans;
	return 0;
}
posted @ 2025-07-30 21:29  余亦宸  阅读(18)  评论(0)    收藏  举报