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


    1835: [ZJOI2010]base 基站选址

    Time Limit: 100 Sec  Memory Limit: 64 MB
    Submit: 1649  Solved: 761
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    用$dp[i][j]$表示第i个基站建在第j个村庄,转移方程为$dp[i][j]=min(dp[i-1][k]+cost[k][j])+C[j]$;

    $cost[i][j]$表示在从$i$到$j$所需补偿;

    可以预处理出左右两侧能覆盖村庄$i$的最远基站位置$L[i]$和$R[i]$;

    当$j$变为$j+1$时,可能导致一部分原本能被覆盖到的村庄不再被覆盖;

    因此从$j$移动到$j+1$时,对于所有$R[k]==j$的$k$,把区间$[1,L[k]-1]$加上$W[k]$;

    区间最小值+区间加,可以用线段树维护;

    枚举建造基站的个数,每次重建线段树,最终$ans=min(dp[i][j]+sum[j])$;

    其中$sum[j]$表示最后一个基站建在$j$时,$j$右侧村庄所需补偿,计算方式与$cost$数组类似;

    复杂度$O(knlogn)$;

    AC GET☆DAZE

     
    ↓代码
      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<string>
      6 #include<vector>
      7 #include<bitset>
      8 #include<cmath>
      9 #include<queue>
     10 #include<ctime>
     11 #include<map>
     12 #include<set>
     13 #define N 20039
     14 #define ll long long
     15 #define inf 0x3f3f3f3f
     16 using namespace std;
     17 struct seg
     18 {
     19     int l,r,w,lazy;
     20 }tree[N<<3];
     21 int x[N],L[N],R[N],co[N],rw[N],sum[N],dp[N],ans,stp;
     22 bool use[N];
     23 vector<int> inl[N],inr[N];
     24 void pull_up(int k)
     25 {
     26     tree[k].w=min(tree[k<<1].w,tree[k<<1|1].w);
     27 }
     28 void push_down(int k)
     29 {
     30     if(tree[k].lazy)
     31     {
     32         tree[k<<1].w+=tree[k].lazy,tree[k<<1|1].w+=tree[k].lazy;
     33         tree[k<<1].lazy+=tree[k].lazy,tree[k<<1|1].lazy+=tree[k].lazy;
     34         tree[k].lazy=0;
     35     }
     36 }
     37 void build(int k,int l,int r)
     38 {
     39     tree[k].l=l,tree[k].r=r,tree[k].lazy=0;
     40     if(l==r)
     41     {
     42         tree[k].w=dp[l];
     43         return; 
     44     }
     45     int mid=l+r>>1;
     46     build(k<<1,l,mid);
     47     build(k<<1|1,mid+1,r);
     48     pull_up(k);
     49 }
     50 void update(int k,int l,int r,int v)
     51 {
     52     if(l>r)
     53     {
     54         return;
     55     }
     56     push_down(k);
     57     if(tree[k].l>=l && tree[k].r<=r)
     58     {
     59         tree[k].w+=v;
     60         tree[k].lazy+=v;
     61         return;
     62     }
     63     int mid=tree[k].l+tree[k].r>>1;
     64     if(mid>=r)
     65     {
     66         update(k<<1,l,r,v);
     67     }
     68     else if(mid<l)
     69     {
     70         update(k<<1|1,l,r,v);
     71     }
     72     else
     73     {
     74         update(k<<1,l,r,v),update(k<<1|1,l,r,v);
     75     }
     76     pull_up(k);
     77 }
     78 int query(int k,int l,int r)
     79 {
     80     if(l>r)
     81     {
     82         return 0;
     83     }
     84     push_down(k);
     85     if(tree[k].l>=l && tree[k].r<=r)
     86     {
     87         return tree[k].w;
     88     }
     89     int mid=tree[k].l+tree[k].r>>1;
     90     if(mid>=r)
     91     {
     92         return query(k<<1,l,r);
     93     }
     94     else if(mid<l)
     95     {
     96         return query(k<<1|1,l,r);
     97     }
     98     else
     99     {
    100         return min(query(k<<1,l,r),query(k<<1|1,l,r));
    101     }
    102 }
    103 int main()
    104 {
    105     int n,k,a,b,c;
    106     scanf("%d%d",&n,&k);
    107     for(a=2;a<=n;a++)
    108     {
    109         scanf("%d",&x[a]);
    110     }
    111     for(a=1;a<=n;a++)
    112     {
    113         scanf("%d",&co[a]);
    114     }
    115     for(a=1;a<=n;a++)
    116     {
    117         scanf("%d",&b);
    118         L[a]=lower_bound(x+1,x+n+1,x[a]-b)-x;
    119         R[a]=lower_bound(x+1,x+n+1,x[a]+b)-x;
    120         if(x[R[a]]>x[a]+b)
    121         {
    122             R[a]--;
    123         }
    124         inl[L[a]].push_back(a);
    125         inr[R[a]].push_back(a);
    126     }
    127     for(a=1;a<=n;a++)
    128     {
    129         scanf("%d",&rw[a]);
    130         ans+=rw[a];
    131     }
    132     for(a=1,stp=ans;a<=n;a++)
    133     {
    134         for(b=0;b<inl[a].size();b++)
    135         {
    136             if(!use[inl[a][b]])
    137             {
    138                 stp-=rw[inl[a][b]];
    139             }
    140             use[inl[a][b]]=1;
    141         }
    142         sum[a]=stp;
    143     }
    144     for(a=1;a<=k;a++)
    145     {
    146         if(a==1)
    147         {
    148             for(b=1,stp=0;b<=n;b++)
    149             {
    150                 dp[b]=stp+co[b];
    151                 for(c=0;c<inr[b].size();c++)
    152                 {
    153                     stp+=rw[inr[b][c]];
    154                 }
    155                 ans=min(ans,dp[b]+sum[b]);
    156             }
    157             continue;
    158         }
    159         build(1,1,n);
    160         for(b=1;b<=n;b++)
    161         {
    162             dp[b]=query(1,1,b-1)+co[b];
    163             for(c=0;c<inr[b].size();c++)
    164             {
    165                 update(1,1,L[inr[b][c]]-1,rw[inr[b][c]]);
    166             }
    167             ans=min(ans,dp[b]+sum[b]);
    168         }
    169     }
    170     printf("%d",ans);
    171     return 0;
    172 }
    bzoj1835
  • 相关阅读:
    构建企业级数据湖?Azure Data Lake Storage Gen2实战体验(中)
    构建企业级数据湖?Azure Data Lake Storage Gen2实战体验(上)
    寻觅Azure上的Athena和BigQuery (二):神奇的PolyBase
    寻觅Azure上的Athena和BigQuery(一):落寞的ADLA
    Azure中国CDN全球覆盖功能初探
    第一次负责项目感悟
    C#读取静态类常量属性和值
    std::thread使用
    C#泛型编程
    C++模板类
  • 原文地址:https://www.cnblogs.com/Sinogi/p/7710562.html
Copyright © 2020-2023  润新知