[ZJOI2010]基站选址

题目描述

有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就村庄被基站覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。

输入输出格式

输入格式:

输入文件的第一行包含两个整数N,K,含义如上所述。

第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。

第三行包含N个整数,表示C1,C2,…CN。

第四行包含N个整数,表示S1,S2,…,SN。

第五行包含N个整数,表示W1,W2,…,WN。

输出格式:

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

输入输出样例

输入样例#1: 复制
3 2
1 2
2 3 2
1 1 0
10 20 30
输出样例#1: 复制
4

说明

40%的数据中,N<=500;

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

转自Navi_Awson

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long lol;
struct Node
{
    int next,to;
} edge[20005];
int head[20005],num;
lol Min[81005],f[20005];
lol lazy[81005];
int n,k,d[20005],c[20005],l[20005],w[20005];
int st[20005],ed[20005],inf=1e15;
lol ans,now;
void add(int u,int v)
{
    num++;
    edge[num].next=head[u];
    head[u]=num;
    edge[num].to=v;
}
void build(int rt,int l,int r)
{
    lazy[rt]=0;
    if (l==r)
    {
        Min[rt]=f[l];
        return;
    }
    int mid=(l+r)/2;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
}
void pushdown(int rt)
{
    if (lazy[rt])
    {
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        Min[rt<<1]+=lazy[rt];
        Min[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}
void update(int rt,int l,int r,int L,int R,lol d)
{
    if (l>=L&&r<=R)
    {
        Min[rt]+=d;
        lazy[rt]+=d;
        return;
    }
    int mid=(l+r)/2;
    pushdown(rt);
    if (L<=mid) update(rt<<1,l,mid,L,R,d);
    if (R>mid) update(rt<<1|1,mid+1,r,L,R,d);
    Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
}
lol query(int rt,int l,int r,int L,int R)
{
    if (l>=L&&r<=R)
    {
        return Min[rt];
    }
    int mid=(l+r)/2;
    lol s=2e15;
    pushdown(rt);
    if (L<=mid) s=min(s,query(rt<<1,l,mid,L,R));
    if (R>mid) s=min(s,query(rt<<1|1,mid+1,r,L,R));
    Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
    return s;
}
int main()
{
    int i,j,p;  
    cin>>n>>k;
    for (i=2; i<=n; i++)
        scanf("%d",&d[i]);
    for (i=1; i<=n; i++)
        scanf("%d",&c[i]);
    for (i=1; i<=n; i++)
        scanf("%d",&l[i]);
    for (i=1; i<=n; i++)
        scanf("%d",&w[i]);
    ++n;
    ++k;
    w[n]=inf;
    d[n]=inf;
    for (i=1; i<=n; i++)
    {
        st[i]=lower_bound(d+1,d+n+1,d[i]-l[i])-d;
        ed[i]=lower_bound(d+1,d+n+1,d[i]+l[i])-d;
        if (d[ed[i]]>d[i]+l[i]) ed[i]--;
        add(ed[i],i);
    }
    ans=2e15;
    for (i=1; i<=n; i++)
    {
        f[i]=now+c[i];
        for (j=head[i]; j; j=edge[j].next)
        {
            int v=edge[j].to;
            now+=w[v];
        }
    }
    ans=min(ans,f[n]);
    for (i=2; i<=k; i++)
    {
        build(1,1,n);
        for (j=1; j<=n; j++)
        {
            if (j>1)
                f[j]=query(1,1,n,1,j-1)+c[j];
            else f[j]=c[j];
            for (p=head[j]; p; p=edge[p].next)
            {
                int v=edge[p].to;
                if (st[v]>1) update(1,1,n,1,st[v]-1,w[v]);
            }
        }
        ans=min(ans,f[n]);
    }
    cout<<ans;
}

 

posted @ 2018-03-30 21:13  Z-Y-Y-S  阅读(258)  评论(0编辑  收藏  举报