P2605 [ZJOI2010]基站选址
#
一道比较简单线段树优化,但它是黑色的!!!
一个显然的,设表示选到第个(必选),建了个基站。
表示到中没被覆盖的村庄的补偿总费用
这样是
发现对于一个村庄,如果转移的不在区间内就会加,那么就可以用线段树维护值,对区间的数加上即可。
最后的答案在随便处理一下即可。
#
#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);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?