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


    Description

    有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。

    Input

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

    Output

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

    Sample Input

    4

    Sample Output

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

    解题思路:

    一道好题,不过我没时间写题解了,暂且咕在这里。

    代码:

      1 #include<cstdio>
      2 #include<vector>
      3 #include<cstring>
      4 #include<algorithm>
      5 #define lll spc<<1
      6 #define rrr spc<<1|1
      7 typedef long long lnt;
      8 const int N=30010;
      9 struct trnt{
     10     lnt lzt;
     11     lnt minv;
     12 }tr[N<<2],stt;
     13 int n,k;
     14 lnt w[N],s[N],d[N],c[N];
     15 int lp[N],rp[N];
     16 lnt dp[N];
     17 std::vector<lnt>lim[N];
     18 void pushup(int spc)
     19 {
     20     tr[spc].minv=std::min(tr[lll].minv,tr[rrr].minv);
     21     return ;
     22 }
     23 void add(int spc,lnt v)
     24 {
     25     tr[spc].minv+=v;
     26     tr[spc].lzt+=v;
     27     return ;
     28 }
     29 void pushdown(int spc)
     30 {
     31     if(tr[spc].lzt)
     32     {
     33         add(lll,tr[spc].lzt);
     34         add(rrr,tr[spc].lzt);
     35         tr[spc].lzt=0;
     36     }
     37     return ;
     38 }
     39 void build(int l,int r,int spc)
     40 {
     41     tr[spc]=stt;
     42     if(l==r)
     43     {
     44         tr[spc].minv=dp[l];
     45         return ;
     46     }
     47     int mid=(l+r)>>1;
     48     build(l,mid,lll);
     49     build(mid+1,r,rrr);
     50     pushup(spc);
     51     return ;
     52 }
     53 void update(int l,int r,int ll,int rr,int spc,lnt v)
     54 {
     55     if(l>rr||ll>r)
     56         return ;
     57     if(ll<=l&&r<=rr)
     58     {
     59         add(spc,v);
     60         return ;
     61     }
     62     int mid=(l+r)>>1;
     63     pushdown(spc);
     64     update(l,mid,ll,rr,lll,v);
     65     update(mid+1,r,ll,rr,rrr,v);
     66     pushup(spc);
     67     return ;
     68 }
     69 lnt query(int l,int r,int ll,int rr,int spc)
     70 {
     71     if(l>rr||ll>r)
     72         return 0x3f3f3f3f;
     73     if(ll<=l&&r<=rr)
     74         return tr[spc].minv;
     75     int mid=(l+r)>>1;
     76     pushdown(spc);
     77     return std::min(query(l,mid,ll,rr,lll),query(mid+1,r,ll,rr,rrr));
     78 }
     79 int main()
     80 {
     81     scanf("%d%d",&n,&k);
     82     for(int i=2;i<=n;i++)
     83         scanf("%lld",&d[i]);
     84     for(int i=1;i<=n;i++)
     85         scanf("%lld",&c[i]);
     86     for(int i=1;i<=n;i++)
     87         scanf("%lld",&s[i]);
     88     for(int i=1;i<=n;i++)
     89         scanf("%lld",&w[i]);
     90     for(int i=1;i<=n;i++)
     91     {
     92         lp[i]=rp[i]=i;
     93         int l=1,r=i-1;
     94         while(l<=r)
     95         {
     96             int mid=(l+r)>>1;
     97             if(d[i]-d[mid]<=s[i])
     98             {
     99                 r=mid-1;
    100                 lp[i]=mid;
    101             }else
    102                 l=mid+1;
    103         }
    104         l=i+1,r=n;
    105         while(l<=r)
    106         {
    107             int mid=(l+r)>>1;
    108             if(d[mid]-d[i]<=s[i])
    109             {
    110                 l=mid+1;
    111                 rp[i]=mid;
    112             }else
    113                 r=mid-1;
    114         }
    115         lim[rp[i]].push_back(i);
    116     }
    117     lnt sum=0;
    118     for(int i=1;i<=n;i++)
    119     {
    120         dp[i]=c[i]+sum;
    121         for(int j=0;j<lim[i].size();j++)
    122             sum+=w[lim[i][j]];
    123     }
    124     lnt ans=sum;
    125     for(int i=1;i<=k;i++)
    126     {
    127         build(1,n,1);
    128         for(int j=1;j<=n;j++)
    129         {
    130             dp[j]=query(1,n,1,j-1,1)+c[j];
    131             for(int o=0;o<lim[j].size();o++)
    132                 update(1,n,1,lp[lim[j][o]]-1,1,w[lim[j][o]]);
    133         }
    134         ans=std::min(ans,query(1,n,1,n,1));
    135     }
    136     printf("%lld
    ",ans);
    137     return 0;
    138 }
  • 相关阅读:
    Redis网络连接库剖析
    如何下载和安装pywin32
    Python游戏开发入门:pygame事件处理机制
    python常见错误
    波特率与比特率
    __gcd最大公约数
    动态规划算法之矩阵连乘问题
    二分插入排序+二分搜索
    office 总结
    javaWeb总结
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/10205800.html
Copyright © 2020-2023  润新知