G. base 基站选址

内存限制:128 MiB 时间限制:2000 ms 标准输入输出
题目类型:传统 评测方式:文本比较
 

题目描述

有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。

输入格式

输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述。 第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。 第三行包含N个整数,表示C1,C2,…CN。 第四行包含N个整数,表示S1,S2,…,SN。 第五行包含N个整数,表示W1,W2,…,WN。

输出格式

输出文件中仅包含一个整数,表示最小的总费用。

样例

样例输入

3 2 1 2 2 3 2 1 1 0 10 20 30

样例输出

4

数据范围与提示

40%的数据中,N<=500; 100%的数据中,K<=N,K<=100,N<=20,000,Di<=1000000000,Ci<=10000,Si<=1000000000,Wi<=10000。


 1.lazy标记打错了,应该是 += ,不能直接覆盖
    2.lc<<1 打成了 >>1 ,调了半天
    3.优化思路:首先是每个村庄的左右端点,二分查找并记录
    DP方程 f[i][j]=min(f[k][j-1]+pay[x])+c[i],表示第 j 个基站建在第 i 个村庄时的最小花费,不考虑 i+1 到 n
    显然,可以去掉一维
    f[i]=min(f[i]+pay[x])+c[i];
    此时,考虑优化计算 pay[x] ,也就是没有被覆盖的点的花费
    因为若 ed[x]=i,此时 i 不被选择,那么 计算 i+1 时就要加上花费
    所以,我们应维护一个区间,存储上一个基站建在 i 时的最小花费之和 ,即 f[k][j-1]+pay[x];
    在计算时,查找 [1,i-1]的最小值
    然后更新所有以 i 为右端点的村庄的花费,区间为 [1,st[x]-1];
    最后,因为我们考虑的是当前点对前面的影响,所以我们在最后新建一个假点,用来保存结果

  个人总结:把线段树当成一种工具,可以快速存储,查找想要的值,利用这一特性我们有规律地存储我们想要的值。可达到大大节约时间的目的

代码:

#include<bits/stdc++.h>
#define re register int
#define int long long
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
const int N=2e4+10;
const int INF=1e12+7;
int n,k,tot,num;
int dis[N],c[N],s[N],w[N],st[N],ed[N];
struct TREE
{
    int zh,lazy;
}use[N*40];
long long f[N];
int to[N<<1],next[N<<1],head[N<<1];
void add(int x,int y)
{
    to[++tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}
void pp(int p)
{
    use[p].zh=min(use[lc].zh,use[rc].zh);
}
void pd(int p)
{
    if(!use[p].lazy)
        return;
    use[lc].lazy+=use[p].lazy;
    use[rc].lazy+=use[p].lazy;
    use[lc].zh+=use[p].lazy;
    use[rc].zh+=use[p].lazy;
    use[p].lazy=0;
}
void build(int p,int l,int r)
{
    use[p].lazy=0;
    if(l==r)
    {
        use[p].zh=f[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    pp(p);
}
int query(int p,int L,int R,int l,int r)
{
    if(l>r)
        return INF;
    if(l<=L&&R<=r)
        return use[p].zh;
    int mid=(L+R)>>1;
    int ans=INF;
    pd(p);
    if(l<=mid)
        ans=min(ans,query(lc,L,mid,l,r));
    if(mid<r)
        ans=min(ans,query(rc,mid+1,R,l,r));
    return ans;
}
void change(int p,int L,int R,int l,int r,int z)
{
    if(l>r)
        return;
    if(l<=L&&R<=r)
    {
        use[p].zh+=z;
        use[p].lazy+=z;
        return;
    }
    int mid=(L+R)>>1;
    pd(p);
    if(l<=mid)
        change(lc,L,mid,l,r,z);
    if(mid<r)
        change(rc,mid+1,R,l,r,z);
    pp(p);
}
signed main()
{
    scanf("%lld%lld",&n,&k);
    for(re i=2;i<=n;i++)
        scanf("%lld",&dis[i]);
    for(re i=1;i<=n;i++)
        scanf("%lld",&c[i]);
    for(re i=1;i<=n;i++)
        scanf("%lld",&s[i]);
    for(re i=1;i<=n;i++)
        scanf("%lld",&w[i]);
    ++n;
    ++k;
    dis[n]=INF;
    w[n]=INF;
    for(re i=1;i<=n;i++)
    {
        st[i]=lower_bound(dis+1,dis+n+1,max(dis[i]-s[i],0*1ll))-dis;
        ed[i]=upper_bound(dis+1,dis+n+1,min(dis[i]+s[i],dis[n]))-dis;
        ed[i]-=1;
        add(ed[i],i);    
    }
    int sum=0;
    for(re i=1;i<=n;i++)
    {
        f[i]=sum+c[i];
        for(re j=head[i];j;j=next[j])
            sum+=w[to[j]];
    }
    int out=f[n];
    for(re i=2;i<=k;i++)
    {
        build(1,1,n);
        for(re j=1;j<=n;j++)
        {
            f[j]=query(1,1,n,1,j-1)+c[j];
            for(re k=head[j];k;k=next[k])
            {
                int p=to[k];
                change(1,1,n,1,st[p]-1,w[p]);
            }
        }
        out=min(out,f[n]);
    }
    printf("%lld\n",out);
}

[ZJOI2010]基站选址,线段树优化DP的更多相关文章

  1. 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$

    正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...

  2. luogu P2605 [ZJOI2010]基站选址 线段树优化dp

    LINK:基站选址 md气死我了l达成1结果一直调 显然一个点只建立一个基站 然后可以从左到右进行dp. \(f_{i,j}\)表示强制在i处建立第j个基站的最小值. 暴力枚举转移 复杂度\(n\cd ...

  3. BZOJ 1835 [ZJOI2010]基站选址 (线段树优化DP)

    题目大意:略 洛谷题面传送门 BZOJ题面传送门 注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了 定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一 ...

  4. luogu2605 基站选址 (线段树优化dp)

    设f[i][j]表示在第i个村庄建第j个基站的花费 那么有$f[i][j]=min\{f[k][j-1]+w[k,i]\}$,其中w[k,i]表示在k,i建基站,k,i中间的不能被满足的村庄的赔偿金之 ...

  5. BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)

    Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...

  6. Codeforces Round #426 (Div. 2) D 线段树优化dp

    D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  7. BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】

    BZOJ2090: [Poi2010]Monotonicity 2[线段树优化DP] Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. ...

  8. [AGC011F] Train Service Planning [线段树优化dp+思维]

    思路 模意义 这题真tm有意思 我上下楼梯了半天做出来的qwq 首先,考虑到每K分钟有一辆车,那么可以把所有的操作都放到模$K$意义下进行 这时,我们只需要考虑两边的两辆车就好了. 定义一些称呼: 上 ...

  9. 【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp

    题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a varian ...

随机推荐

  1. 《MySQL面试小抄》索引失效场景验证

    我是肥哥,一名不专业的面试官! 我是囧囧,一名积极找工作的小菜鸟! 囧囧表示:小白面试最怕的就是面试官问的知识点太笼统,自己无法快速定位到关键问题点!!! 本期主要面试考点 面试官考点之什么情况下会索 ...

  2. Redmine部署中遇到的问题

    Redmine部署文章: 第一篇:Redmine部署 第二篇:Redmine部署中遇到的问题 上一篇文章我写了Redmine怎样部署(点这里直达上一篇文章),这一篇就写一下在Redmine部署中遇到过 ...

  3. Redisson 分布式锁源码 01:可重入锁加锁

    前言 相信小伙伴都是使用分布式服务,那一定绕不开分布式服务中数据并发更新问题! 单系统很容易想到 Java 的各种锁,像 synchronize.ReentrantLock 等等等,那分布式系统如何处 ...

  4. python安装、卸载包的方法

    anaconda包管理器 conda命令[1] 环境管理 conda info -e # 查看当前已安装的环境 conda create -n py27 python=2.7 # 添加2.7版本的Py ...

  5. Excel选择区域一次性替换小于200的数值

    1.ctrl+F,点击"选项",在出来的扩展框选择"格式"后小三角,选择"从单元格选择格式": 2.选择要进行替换小于200的区域: . 3 ...

  6. 最强阿里巴巴历年经典面试题汇总:C++研发岗

    (1).B树.存储模型 (2).字典树构造及其优化与应用 (3).持久化数据结构,序列化与反序列化时机(4).在无序数组中找最大的K个数? (4).大规模文本文件,全是单词,求前10词频的单词 (5) ...

  7. 12、Linux磁盘设备基础知识(2)

    12.4.计算磁盘容量: 磁盘的大小=盘面大小*磁头数 盘面的大小=磁道大小*磁道数 磁道大小=512字节*扇区数 磁盘的大小=512字节*扇区数*磁道数*磁头数 磁盘的大小=柱面大小*柱面数 柱面大 ...

  8. Centos 8 误删/boot文件夹下文件后的恢复

    一.环境 Centos8 二.过程 1.查看/boot底下文件 ls /boot 2.模拟误删/boot底下文件 rm -rf /boot/*ls /boot 3.reboot,无法正常启动 4.在v ...

  9. hadoop学习(三)HDFS常用命令以及java操作HDFS

    一.HDFS的常用命令 1.查看根目录下的信息:./hadoop dfs -ls 2.查看根目录下的in目录中的内容:./hadoop dfs -ls in或者./hadoop dfs -ls ./i ...

  10. 0shell变量

    1.定义变量 2.使用变量 3.修改变量的值 4.将命令的结果赋值给变量 5.只读变量 6.删除变量 一.变量 1.定义变量 在 Bash shell 中,每一个变量的值都是字符串,无论你给变量赋值时 ...