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


    题目大意:略 洛谷题面传送门 BZOJ题面传送门

    注意题目的描述,是村庄在一个范围内去覆盖基站,而不是基站覆盖村庄,别理解错了

    定义$f[i][k]$表示只考虑前i个村庄,一共建了$k$个基站,最后一个基站建在了i处,最小的总花费

    $f[i][k]=min(f[j][k]+calc(j,i));calc(j,i)$表示$i$和$j$之间,无法被覆盖的点,需要付的补偿总和

    考虑如何求出$calc(j,i)$

    定义$st_{i}$,$ed_{i}$表示第$i$个村庄能覆盖的最左端点和最右端点

    即$st_{i}$到$ed_{i}$之间只要有一个村庄有基站,那么村庄i就不需要被补偿

    可以用二分查找实现

    把相同$ed_{i}$的村庄编号记录在$ed_{i}$这个位置

    $DP$时,我们从左往右遍历要建基站的位置$x$,如果有一个村庄$i$的$ed_{i}<$当前位置$x$,那么如果$x$的决策如果选在了$[1,st_{i}-1]$,即上一个基站建在了$[1,st_{i}-1]$,那么村庄$i$需要被补偿,区间修改,用线段树实现

    而转移就是查询区间最小值,同样用线段树实现即可

    细节略多

      1 #include <vector>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define N1 20010
      6 #define K1 105
      7 #define ll long long
      8 #define dd double
      9 #define inf 0x3f3f3f3f3f3f3f3fll
     10 using namespace std;
     11 
     12 int gint()
     13 {
     14     int ret=0,fh=1;char c=getchar();
     15     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     16     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     17     return ret*fh;
     18 }
     19 
     20 struct SEG{
     21 ll mi[N1<<2],tag[N1<<2];
     22 inline void pushup(int rt){ mi[rt]=min(mi[rt<<1],mi[rt<<1|1]); }
     23 inline void pushdown(int rt)
     24 {
     25     if(!tag[rt]) return;
     26     mi[rt<<1]+=tag[rt]; mi[rt<<1|1]+=tag[rt];
     27     tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt];
     28     tag[rt]=0;
     29 }
     30 void build(ll *f,int l,int r,int rt)
     31 {
     32     tag[rt]=0;
     33     if(l==r){ mi[rt]=f[l]; return; } 
     34     int mid=(l+r)>>1;
     35     build(f,l,mid,rt<<1);
     36     build(f,mid+1,r,rt<<1|1);
     37     pushup(rt);
     38 }
     39 void update(int L,int R,int l,int r,int rt,ll w)
     40 {
     41     if(L<=l&&r<=R){ mi[rt]+=w; tag[rt]+=w; return; }
     42     int mid=(l+r)>>1; pushdown(rt);
     43     if(L<=mid) update(L,R,l,mid,rt<<1,w);
     44     if(R>mid) update(L,R,mid+1,r,rt<<1|1,w);
     45     pushup(rt);
     46 }
     47 ll query(int L,int R,int l,int r,int rt)
     48 {
     49     if(L<=l&&r<=R) return mi[rt];
     50     int mid=(l+r)>>1; ll ans=inf; pushdown(rt); 
     51     if(L<=mid) ans=min(ans,query(L,R,l,mid,rt<<1));
     52     if(R>mid) ans=min(ans,query(L,R,mid+1,r,rt<<1|1));
     53     return ans;
     54 }
     55 }s;
     56 
     57 vector<int>id[N1];
     58 int n,K;
     59 int d[N1],c[N1],p[N1],w[N1],st[N1],ed[N1];
     60 ll f[N1];
     61 
     62 int main()
     63 {
     64     scanf("%d%d",&n,&K);
     65     int i,j,k,l,r,x,mid; ll ans=inf;
     66     for(i=2;i<=n;i++) d[i]=gint();
     67     for(i=1;i<=n;i++) c[i]=gint();
     68     for(i=1;i<=n;i++) p[i]=gint();
     69     for(i=1;i<=n;i++) w[i]=gint();
     70     for(i=1;i<=n;i++)
     71     {
     72         l=1,r=i,st[i]=i;
     73         while(l<=r)
     74         {
     75             mid=(l+r)>>1;
     76             if(d[mid]>=d[i]-p[i]) st[i]=mid,r=mid-1;
     77             else l=mid+1;
     78         }
     79         l=i,r=n,ed[i]=i;
     80         while(l<=r)
     81         {
     82             mid=(l+r)>>1;
     83             if(d[mid]<=d[i]+p[i]) ed[i]=mid,l=mid+1;
     84             else r=mid-1;
     85         }
     86         id[ed[i]].push_back(i);
     87     }
     88     memset(s.mi,0x3f,sizeof(s.mi));
     89     s.update(0,0,0,n,1,-(inf));
     90     for(k=1;k<=K;k++)
     91     {
     92         for(i=1;i<=n+1;i++)
     93         {
     94             f[i]=s.query(0,i-1,0,n,1)+c[i];
     95             for(j=0;j<id[i].size();j++)
     96             {
     97                 x=id[i][j];
     98                 s.update(0,st[x]-1,0,n,1,w[x]);
     99             }
    100         }
    101         ans=min(ans,f[n+1]);
    102         s.build(f,0,n,1);
    103     }
    104     for(i=1;i<=n;i++)
    105     {
    106         for(j=0;j<id[i].size();j++)
    107         {
    108             x=id[i][j];
    109             s.update(0,st[x]-1,0,n,1,w[x]);
    110         }
    111     }
    112     ans=min(ans,s.query(0,n,0,n,1));
    113     printf("%lld
    ",ans);
    114     return 0;
    115 }
  • 相关阅读:
    NPIV介绍
    PowerShell随笔2_分支 选择 循环 特殊变量
    socket编程原理
    Linux查看物理CPU个数、核数、逻辑CPU个数
    Markdown 使用指南
    Linux Socket
    YoutubeAPI使用
    Youtube API数据类型
    Linux wpa_cli 调试方法
    linux网络编程
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10262701.html
Copyright © 2020-2023  润新知