P2605 [ZJOI2010]基站选址

\(\text{Solution}\)

一道比较简单线段树优化\(DP\),但它是黑色的!!!
一个显然的\(DP\),设\(f_{i,j}\)表示选到第\(i\)个(\(i\)必选),建了\(j\)个基站。

\[f_{i,j} = f_{k,j - 1} + Sw_{k,i} + C_i \]

\(Sw_{i,j}\)表示\(i\)\(j\)中没被覆盖的村庄的补偿总费用
这样\(DP\)\(O(n^2)\)
发现对于一个村庄\(x\),如果转移的\(j\)不在区间\([x - S_x,x + S_x]\)内就会加\(W_x\),那么就可以用线段树维护\(DP\)值,对区间\([1,x - S_x - 1]\)的数加上\(W_x\)即可。
最后的答案在随便处理一下即可。

\(\text{Code}\)

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 2e4 + 5,inf = 1e9;
int n,m,d[N],c[N],w[N],f[N << 2],tag[N << 2],g[N][105];

struct nd{int l,r,id;}a[N];
bool cmp(nd x,nd y){return x.r < y.r;}
void build(int l,int r,int k,int x)
{
	tag[k] = 0;
	if (l == r) return f[k] = g[l][x],void();
	int mid = l + r >> 1;
	build(l,mid,k << 1,x),build(mid + 1,r,k << 1 | 1,x);
	f[k] = min(f[k << 1],f[k << 1 | 1]);
}
void pushdown(int k)
{
	if (!tag[k]) return;
	tag[k << 1] += tag[k],tag[k << 1 | 1] += tag[k];
	f[k << 1] += tag[k],f[k << 1 | 1] += tag[k],tag[k] = 0;
}
void update(int l,int r,int k,int L,int R,int v)
{
	if (L > R || l > R || r < L || !v) return;
	if (L <= l && r <= R) return f[k] += v,tag[k] += v,void();
	pushdown(k); int mid = l + r >> 1;
	if (L <= mid) update(l,mid,k << 1,L,R,v);
	if (R > mid) update(mid + 1,r,k << 1 | 1,L,R,v);
	f[k] = min(f[k << 1],f[k << 1 | 1]);
}
int query(int l,int r,int k,int L,int R)
{
	if (L <= l && r <= R) return f[k];
	pushdown(k); int mid = l + r >> 1,tmp = inf;
	if (L <= mid) tmp = query(l,mid,k << 1,L,R);
	if (R > mid) tmp = min(tmp,query(mid + 1,r,k << 1 | 1,L,R));
	return tmp;
}
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",&c[i]);
	for (int i = 1,s; i <= n; i++)
	{
		scanf("%d",&s),a[i] = nd{d[i] - s,d[i] + s,i};
		int l = 1,r = n,res = 1;
		while (l <= r) {
			int mid = l + r >> 1;
			if (d[mid] >= a[i].l) res = mid,r = mid - 1;
			else l = mid + 1;
		}a[i].l = res,l = 1,r = n,res = n; 
		while (l <= r) {
			int mid = l + r >> 1;
			if (d[mid] <= a[i].r) res = mid,l = mid + 1;
			else r = mid - 1;
		}a[i].r = res;
	}
	for (int i = 1; i <= n; i++) scanf("%d",&w[i]);
	n++,a[n] = nd{n,n,n}; 
	sort(a + 1,a + 1 + n,cmp); int ans = inf;
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= m; j++) g[i][j] = inf; 
	g[0][0] = 0;
	for (int j = 1; j <= m + 1; j++)
	{
		build(0,n,1,j - 1);
		for (int i = 1,k = 1; i <= n; i++)
		{
			while (k <= n && a[k].r < i) update(0,n,1,0,a[k].l - 1,w[a[k].id]),k++;
			g[i][j] = query(0,n,1,0,i - 1) + c[i]; 
		}
	}
	for (int i = 1; i <= m + 1; i++) ans = min(ans,g[n][i]);
	printf("%d\n",ans);
}
posted @ 2022-03-16 19:14  RiverSheep  阅读(41)  评论(0)    收藏  举报