zoukankan      html  css  js  c++  java
  • [ZJOI2010]基站选址

    [ZJOI2010]基站选址

    BZOJ权限
    luogu
    考虑朴素的dp,(f[i][j]=min(f[k][j]+cost(k,i)))
    cost(k,i)即在k,i建站中间一些没有被覆盖的点的代价和
    二分出在每个点建站可以覆盖到的区间(st_i,ed_i)
    那么cost就很好计算了
    但这个复杂度依然不对
    我们考虑线段树维护这个东西
    把j放到最外面枚举
    那么转移只要查询维护1~i-1的f[k]+cost(k,i)的最小值就行
    然而cost(k,i)这东西是动态的,假设(ed_p==i)
    我们每次转移i+1时把[1.p]的代价加上(w_p)就好
    每次做完一层重新build
    还有一个细节,为了统计到(ed_p==n)的这些贡献,你需要在最后新加一个dinf,winf的点
    复杂度(O(nklogn))

    #define ls x<<1,l,mid
    #define rs x<<1|1,mid+1,r
    #include<bits/stdc++.h>
    using namespace std;
    const int _=2e4+5;
    int re(){
        int x=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    int n,m,sum,ans;
    vector<int>v[_];
    int d[_],c[_],s[_],w[_],f[_],st[_],ed[_],mn[_<<2],t[_<<2];
    void pu(int x){mn[x]=min(mn[x<<1],mn[x<<1|1]);}
    void bu(int x,int l,int r){
        t[x]=0;if(l==r){mn[x]=f[l];return;}
        int mid=l+r>>1;bu(ls);bu(rs);pu(x);
    }
    void cov(int x,int v){mn[x]+=v;t[x]+=v;}
    void pd(int x){cov(x<<1,t[x]);cov(x<<1|1,t[x]);t[x]=0;}
    void add(int x,int l,int r,int ql,int qr,int v){
        if(ql<=l&&r<=qr){cov(x,v);return;}if(t[x])pd(x);
        int mid=l+r>>1;if(ql<=mid)add(ls,ql,qr,v);
        if(qr>mid)add(rs,ql,qr,v);pu(x);
    }
    int qmin(int x,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr)return mn[x];if(t[x])pd(x);
        int mid=l+r>>1,res=1e9;if(ql<=mid)res=qmin(ls,ql,qr);
        if(qr>mid)res=min(res,qmin(rs,ql,qr));return res;
    }
    int main(){
        n=re()+1,m=re();
        for(int i=2;i<n;i++)d[i]=re();d[n]=1e9;
        for(int i=1;i<n;i++)c[i]=re();
        for(int i=1;i<n;i++)s[i]=re();
        for(int i=1;i<n;i++)w[i]=re();w[n]=1e9;
        for(int i=1;i<=n;i++){
            st[i]=lower_bound(d+1,d+n+1,d[i]-s[i])-d;
            ed[i]=upper_bound(d+1,d+n+1,d[i]+s[i])-d-1;
            v[ed[i]].push_back(i);
        }
        for(int i=1;i<=n;i++){
            f[i]=sum+c[i];
            for(int j=0,k=v[i].size();j<k;j++)
                sum+=w[v[i][j]];
        }
        ans=f[n];
        while(m--){
            bu(1,1,n);
            for(int i=1;i<=n;i++){
                if(i>1)f[i]=qmin(1,1,n,1,i-1)+c[i];
                else f[i]=c[i];
                for(int j=0,k=v[i].size();j<k;j++){
                    int x=v[i][j];
                    if(st[x]>1)add(1,1,n,1,st[x]-1,w[x]);
                }
            }
            ans=min(ans,f[n]);
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Git:创建远程仓库并推送内容到远程库
    Git中ssh的使用
    Git中的文件上传、修改、撤消修改和删除
    Git的安装和创建版本库
    HTML相关知识点总结
    Android开发--TableLayout的应用
    Java中sql语句的引号问题
    NXOPEN环境配置
    shell小技巧
    查询MySQL锁等待的语句
  • 原文地址:https://www.cnblogs.com/sdzwyq/p/9896123.html
Copyright © 2011-2022 走看看