• bzoj2119 [ZJOI2010]base基站选址


    传送门

    n年前的考试题,今天才填上……

    听说你们会决策单调性+主席树?然而我多年不写决策单调性,懒得写了……于是就写了一发线段树。

    其实线段树应该不难想,毕竟转移是分层转移,并且这个题的转移函数可以快速从$i$更新到$i+1$,这样就给线段树带来了不少方便。

    每个村庄的$s$的限制可以看成一条线段,那么我们在扫过一个线段的右端点时把左端点以左的点都加上这条线段的代价,更新完之后求区间最小值即可,显然可以方便地用线段树来维护区间增量和区间最值。然后就没有然后了。

     1 /**************************************************************
     2     Problem: 1835
     3     User: hzoier
     4     Language: C++
     5     Result: Accepted
     6     Time:6572 ms
     7     Memory:10592 kb
     8 ****************************************************************/
     9 #include<cstdio>
    10 #include<cstring>
    11 #include<algorithm>
    12 using namespace std;
    13 const int maxn=20010,maxk=110;
    14 struct A{
    15     int l,r,w;
    16     bool operator<(const A &a)const{return r<a.r;}
    17 }a[maxn];
    18 void build(int,int,int);
    19 void modify(int,int,int,int,int,int);
    20 int query(int,int,int,int,int);
    21 int mn[maxn<<2],lazy[maxn<<2];
    22 int d[maxn],c[maxn],s[maxn],w[maxn];
    23 int n,m,k,f[maxn][maxk],ans=0;
    24 int main(){
    25     scanf("%d%d",&n,&m);
    26     for(int i=2;i<=n;i++)scanf("%d",&d[i]);
    27     for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    28     for(int i=1;i<=n;i++)scanf("%d",&s[i]);
    29     for(int i=1;i<=n;i++){
    30         scanf("%d",&a[i].w);
    31         a[i].l=lower_bound(d+1,d+n+1,d[i]-s[i])-d;
    32         a[i].r=upper_bound(d+1,d+n+1,d[i]+s[i])-d-1;
    33         f[a[i].r+1][1]+=a[i].w;
    34         w[a[i].l-1]+=a[i].w;
    35         ans+=a[i].w;//printf("l=%d r=%d w=%d
    ",a[i].l,a[i].r,a[i].w);
    36     }
    37     sort(a+1,a+n+1);
    38     for(int i=1;i<=n;i++)f[i][1]+=f[i-1][1];
    39     for(int i=n;i;i--)w[i]+=w[i+1];
    40     for(int i=1;i<=n;i++){
    41         f[i][1]+=c[i];
    42         ans=min(ans,f[i][1]+w[i]);
    43     }
    44     //for(int i=1;i<=n;i++)printf("f[%d][0]=%d w=%d
    ",i,f[i][0],w[i]);
    45     f[1][1]=c[1];
    46     for(k=2;k<=m;k++){
    47         int cur=1;
    48         build(1,n,1);
    49         for(int i=k;i<=n;i++){
    50             while(cur<=n&&a[cur].r<i){
    51                 if(a[cur].l>=k)modify(k-1,a[cur].l-1,a[cur].w,1,n,1);//printf("%d~%d += %d
    ",1,a[cur].l-1,a[cur].w);
    52                 cur++;
    53             }
    54             f[i][k]=query(k-1,i-1,1,n,1)+c[i];//printf("f[%d][%d]=%d c[i]=%d
    ",i,k,f[i][k],c[i]);
    55             ans=min(ans,f[i][k]+w[i]);
    56         }
    57     }
    58     printf("%d",ans);
    59     return 0;
    60 }
    61 void build(int l,int r,int rt){
    62     lazy[rt]=0;
    63     if(l==r){
    64         mn[rt]=f[l][k-1];
    65         return;
    66     }
    67     int mid=(l+r)>>1;
    68     build(l,mid,rt<<1);
    69     build(mid+1,r,rt<<1|1);
    70     mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
    71 }
    72 void modify(int s,int t,int d,int l,int r,int rt){
    73     if(s<=l&&t>=r){
    74         mn[rt]+=d;
    75         lazy[rt]+=d;
    76         return;
    77     }
    78     int mid=(l+r)>>1;
    79     if(s<=mid)modify(s,t,d,l,mid,rt<<1);
    80     if(t>mid)modify(s,t,d,mid+1,r,rt<<1|1);
    81     mn[rt]=min(mn[rt<<1],mn[rt<<1|1])+lazy[rt];
    82 }
    83 int query(int s,int t,int l,int r,int rt){
    84     if(s<=l&&t>=r)return mn[rt];
    85     int mid=(l+r)>>1;
    86     if(t<=mid)return query(s,t,l,mid,rt<<1)+lazy[rt];
    87     if(s>mid)return query(s,t,mid+1,r,rt<<1|1)+lazy[rt];
    88     return min(query(s,t,l,mid,rt<<1),query(s,t,mid+1,r,rt<<1|1))+lazy[rt];
    89 }
    View Code
  • 相关阅读:
    字典树略解
    NOIP2018普及组初赛解题报告
    Codeforces 23A You're Given a String...
    远程消息推送的简单方法
    IOS5,6,7的新特性
    面试问题1
    IOS推送消息的步骤
    C面试问题
    label的自适应文本,让文本自适应
    TCP连接的三次握手,TCP/UDP区别联系,socket连接和http连接的区别
  • 原文地址:https://www.cnblogs.com/hzoier/p/6546660.html
Copyright © 2020-2023  润新知