码迷,mamicode.com
首页 > 其他好文 > 详细

P2605 [ZJOI2010]基站选址

时间:2019-02-03 23:31:54      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:简单   lazy   pac   否则   ring   std   getc   cos   端点   

题目

P2605 [ZJOI2010]基站选址

简化题目:1~n个村庄,每个村庄有范围,要求范围内有村庄被选(不超过\(k\)个),否则被罚款,选村庄有一定花费,求最小总花费

做法

朴素
\(dp_{i,j}\)\(j\)个被选的村庄为\(i\)的最小花费:\(dp_{i,k}=min\{dp_{j,k-1}+cost_{i,j}\}+w_i\)

枚举\(k\)(准备选第\(k\)个),\(i\)(具体选\(i\)),\(j\)(上一个被选的),显然\(cost_{i,j}\)预处理\(O(n^2)\),枚举方程\(O(n^2k)\)

时间复杂度度估为\(O(n^2k)\)

优化
习惯地,只出现\(k\)\(k-1\),倒序枚举\(j\)\(dp_{i}=min\{dp_{j}+cost_{i,j}\}+w_i\),还只是优化了点空间而已

最外层\(k\)其实差不多可以不管了\((k<=100)\),主要是优化刚才的这个方程

无后效性,顺序也显然\((j<i)\),考虑这部分\(min\{dp_{j}+cost_{i,j}\}\),最值有关的(\(BIT\)/线段树,单调队列,斜率优化......)

有哪些相同的部分可以利用呢?

假设这次是选\(x\),上一次选\(i\),那\(i\)前面的我们暂时不管,因为之前已经计算过了,我们只用考虑\(i\)~\(k\)中间的赔款

对于上一次选的位置\(i\)\(j\),如果\(i<j\),上一个选\(i\)的赔款肯定包括了\(\longrightarrow\)上一个选\(j\)的赔款

理解:\(i\)~\(x\)\(j\)~\(x\)中间的空区比较多

已经接近了我们的最终思路,假设我们这次在做第\(k\)个选\(i\),设以\(i\)为右端点的村庄为\(x\),其左端点为\(L\),那我们

\(1\)~\(L-1\)都加上\(pay_{x}\)村庄\(x\)的赔款:选\(1\)~\(L-1\)的村庄就不符合\(x\)

诶!!区间查询最小值及位置,区间修改好像线段树做会比较简单

至此,我们已经得到了最终解法:最外层枚举\(k\)(选第k个),第二层枚举选\(i\)(选第i个村庄),然后线段树维护选每个点的赔款及区间最小值

My complete code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
typedef int LL;
const LL maxn=20000+9,inf=0x3f3f3f3f;
inline LL Read(){
    LL x(0),f(1); char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1;c=getchar();
    }
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
struct node{
    LL mn,mni,lazy;
    LL son[2];
}T[maxn<<2];
LL n,ans,nod,K,root;
LL d[maxn],s[maxn],bad[maxn],pay[maxn],dp[maxn],st[maxn],ed[maxn];
vector<LL> belong[maxn];
inline void Update(LL now,LL s1,LL s2){
    if(T[s1].mn<T[s2].mn)
        T[now].mn=T[s1].mn,
        T[now].mni=T[s1].mni;
    else
        T[now].mn=T[s2].mn,
        T[now].mni=T[s2].mni;
}
void Build(LL &now,LL l,LL r){
    if(!now)
        now=++nod;
    T[now].mn=T[now].mni=T[now].lazy=0;
    if(l==r){
        T[now].mn=dp[l],
        T[now].mni=l;
        return;
    }
    LL mid(l+r>>1);
    Build(T[now].son[0],l,mid),
    Build(T[now].son[1],mid+1,r);
    Update(now,T[now].son[0],T[now].son[1]);
}
inline void Pushdown(LL now,LL s1,LL s2){
    LL val(T[now].lazy);
    T[now].lazy=0;
    if(!val)
        return;
    T[s1].lazy+=val,T[s2].lazy+=val,
    T[s1].mn+=val,T[s2].mn+=val;
}
LL Query(LL now,LL l,LL r,LL lt,LL rt){
    if(lt>rt)
        return inf;
    if(lt<=l&&rt>=r)
        return T[now].mn;
    Pushdown(now,T[now].son[0],T[now].son[1]);
    LL mid(l+r>>1),ret=inf;
    if(lt<=mid)
        ret=min(ret,Query(T[now].son[0],l,mid,lt,rt));
    if(rt>mid)
        ret=min(ret,Query(T[now].son[1],mid+1,r,lt,rt));
    return ret;
}
inline void Change(LL now,LL l,LL r,LL lt,LL rt,LL val){
    if(lt>rt)
        return;
    if(lt<=l&&rt>=r){
        T[now].mn+=val,
        T[now].lazy+=val;
        return;
    }
    Pushdown(now,T[now].son[0],T[now].son[1]);
    LL mid(l+r>>1);
    if(lt<=mid)
        Change(T[now].son[0],l,mid,lt,rt,val);
    if(rt>mid)
        Change(T[now].son[1],mid+1,r,lt,rt,val);
    Update(now,T[now].son[0],T[now].son[1]);
}
int main(){
    n=Read(),K=Read();
    for(LL i=2;i<=n;++i)
        d[i]=Read();
    for(LL i=1;i<=n;++i)
        pay[i]=Read();
    for(LL i=1;i<=n;++i)
        s[i]=Read();
    for(LL i=1;i<=n;++i)
        bad[i]=Read();
    d[++n]=inf;
    for(LL i=1;i<=n;++i){
        st[i]=lower_bound(d+1,d+1+n,d[i]-s[i])-d,
        ed[i]=lower_bound(d+1,d+1+n,d[i]+s[i])-d;
        if(d[ed[i]]>d[i]+s[i])
            --ed[i];
        belong[ed[i]].push_back(i);
    }
    LL sum(0);
    for(LL i=1;i<=n;++i){
        dp[i]=sum+pay[i];
        for(LL j=0,size=belong[i].size();j<size;++j)
            sum+=bad[belong[i][j]];
    }
    ans=dp[n];
    ++K;
    for(LL k=2;k<=K;++k){
        Build(root,1,n);
        for(LL i=1;i<=n;++i){
            dp[i]=Query(root,1,n,1,i-1)+pay[i];
            for(LL j=0,size=belong[i].size();j<size;++j){
                LL x(belong[i][j]);
                Change(root,1,n,1,st[x]-1,bad[x]);
            }
        }
        ans=min(ans,dp[n]);
    }
    printf("%d\n",ans);
    return 0;
}

P2605 [ZJOI2010]基站选址

标签:简单   lazy   pac   否则   ring   std   getc   cos   端点   

原文地址:https://www.cnblogs.com/y2823774827y/p/10274063.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!