• LuoguP2605 [ZJOI2010]基站选址 线段树优化DP


    比较好的一道题 DP 题.    

    令 $f[i][j]$ 表示覆盖前 $i$ 个基站且 $i$ 位置上维修了基站的最小代价.   

    注意:上面设的状态是不考虑 $[i+1,n]$ 的.     

    转移的话 $f[i][j] leftarrow f[k][j-1]+calc(j-1,i)$.   

    其中 $calc(i,j)$ 表示 $i$ 和 $j$ 分别修了基站的情况下  $i,j$  之间需要用 $W_{i}$ 的总和.  

    然后这个 $calc(i,j)$ 可以在枚举 $j$ 的时候在线段树上更新.   

    即对于每个位置记录其被管辖范围 $[l,r]$ 然后扫描到 $r+1$ 时将 $[0,l-1]$ 做一个区间加法即可.   

    空间复杂度 $O(n)$,时间复杂度 $O(Kn log n)$. 

    code: 

    #include <cstdio>   
    #include <vector>
    #include <cstring>
    #include <algorithm>     
    #define N 20009  
    #define ll long long    
    #define lson now<<1  
    #define rson now<<1|1   
    #define pb push_back
    #define setIO(s) freopen(s".in","r",stdin)  
    using namespace std;   
    const int inf=1000000009; 
    int n,K; 
    int left[N],right[N],f[N]; 
    int mn[N<<2],lazy[N<<2],dis[N],cost[N],si[N],wi[N];      
    vector<int>g[N];  
    inline void pushup(int now) { 
        mn[now]=min(mn[lson],mn[rson]); 
    }    
    inline void mark(int now,int v) { 
        mn[now]+=v,lazy[now]+=v; 
    } 
    inline void pushdown(int now) { 
        if(lazy[now]) {
            mark(lson,lazy[now]); 
            mark(rson,lazy[now]); 
            lazy[now]=0;
        }
    }
    void build(int l,int r,int now) {  
        lazy[now]=0; 
        if(l==r) { 
            mn[now]=f[l]; 
            return; 
        }  
        int mid=(l+r)>>1;  
        build(l,mid,lson),build(mid+1,r,rson); 
        pushup(now); 
    }   
    int query(int l,int r,int now,int L,int R) { 
        if(l>=L&&r<=R) { 
            return mn[now]; 
        } 
        pushdown(now); 
        int mid=(l+r)>>1,re=inf; 
        if(L<=mid) re=min(re,query(l,mid,lson,L,R)); 
        if(R>mid)  re=min(re,query(mid+1,r,rson,L,R)); 
        return re; 
    }  
    void update(int l,int r,int now,int L,int R,int v) { 
        if(l>=L&&r<=R) { 
            mark(now,v); 
            return; 
        } 
        pushdown(now); 
        int mid=(l+r)>>1; 
        if(L<=mid)  update(l,mid,lson,L,R,v); 
        if(R>mid)   update(mid+1,r,rson,L,R,v);  
        pushup(now); 
    }
    int main() { 
        // setIO("input"); 
        scanf("%d%d",&n,&K);  
        dis[1]=0;  
        for(int i=2;i<=n;++i) scanf("%d",&dis[i]);   
        for(int i=1;i<=n;++i) scanf("%d",&cost[i]); 
        for(int i=1;i<=n;++i) scanf("%d",&si[i]);  
        for(int i=1;i<=n;++i) scanf("%d",&wi[i]);                      
        ++n,++K,cost[n]=0,wi[n]=inf;                      
        for(int i=1;i<n;++i) { 
            int l,r,mid,ans; 
            ans=i,l=1,r=i-1;  
            while(l<=r) { 
                mid=(l+r)>>1;  
                if(dis[i]-si[i]<=dis[mid]) {
                    ans=mid;        
                    r=mid-1; 
                }
                else l=mid+1;  
            }   
            left[i]=ans; 
            ans=i,l=i,r=n-1;   
            while(l<=r) { 
                mid=(l+r)>>1;  
                if(dis[i]+si[i]>=dis[mid]) {
                    ans=mid;  
                    l=mid+1; 
                }
                else r=mid-1; 
            } 
            right[i]=ans;   
            g[right[i]].pb(i);    
        }     
        int ans=inf;  
        for(int j=1;j<=K;++j) { 
            if(j==1) {  
                int tot=0; 
                for(int i=1;i<=n;++i) {     
                    f[i]=tot+cost[i];         
                    for(int j=0;j<g[i].size();++j) {
                        tot+=wi[g[i][j]];  
                    }     
                }             
                ans=min(ans,f[n]);         
            }   
            else {          
                build(0,n,1);         
                for(int i=1;i<=n;++i) {    
                    f[i]=query(0,n,1,0,i-1)+cost[i];                    
                    for(int j=0;j<g[i].size();++j) { 
                        int p=g[i][j];  
                        update(0,n,1,0,left[p]-1,wi[p]);    
                    }
                }
                ans=min(ans,f[n]);
            }
        }
        printf("%d
    ",ans);   
        return 0;
    }
    

      

  • 相关阅读:
    C字符串和C++中string的区别 &amp;&amp;&amp;&amp;C++中int型与string型互相转换
    UML的类图关系分为: 关联、聚合/组合、依赖、泛化(继承)
    STL map详细用法和make_pair函数
    字符串旋转(str.find()---KMP)
    层次遍历二叉树
    图像特征提取三大法宝:HOG特征,LBP特征,Haar特征
    位运算---整数间的转化
    最大公倍数
    单链表的实现
    jsp下Kindeditor环境搭建
  • 原文地址:https://www.cnblogs.com/guangheli/p/13398179.html
Copyright © 2020-2023  润新知