BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)

Description

有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。 输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述。 第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。 第三行包含N个整数,表示C1,C2,…CN。 第四行包含N个整数,表示S1,S2,…,SN。 第五行包含N个整数,表示W1,W2,…,WN。

Input

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

Output

3 2 1 2 2 3 2 1 1 0 10 20 30

Sample Input

4

Sample Output

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

解题思路:

一道好题,不过我没时间写题解了,暂且咕在这里。

代码:

  1 #include<cstdio>
  2 #include<vector>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define lll spc<<1
  6 #define rrr spc<<1|1
  7 typedef long long lnt;
  8 const int N=30010;
  9 struct trnt{
 10     lnt lzt;
 11     lnt minv;
 12 }tr[N<<2],stt;
 13 int n,k;
 14 lnt w[N],s[N],d[N],c[N];
 15 int lp[N],rp[N];
 16 lnt dp[N];
 17 std::vector<lnt>lim[N];
 18 void pushup(int spc)
 19 {
 20     tr[spc].minv=std::min(tr[lll].minv,tr[rrr].minv);
 21     return ;
 22 }
 23 void add(int spc,lnt v)
 24 {
 25     tr[spc].minv+=v;
 26     tr[spc].lzt+=v;
 27     return ;
 28 }
 29 void pushdown(int spc)
 30 {
 31     if(tr[spc].lzt)
 32     {
 33         add(lll,tr[spc].lzt);
 34         add(rrr,tr[spc].lzt);
 35         tr[spc].lzt=0;
 36     }
 37     return ;
 38 }
 39 void build(int l,int r,int spc)
 40 {
 41     tr[spc]=stt;
 42     if(l==r)
 43     {
 44         tr[spc].minv=dp[l];
 45         return ;
 46     }
 47     int mid=(l+r)>>1;
 48     build(l,mid,lll);
 49     build(mid+1,r,rrr);
 50     pushup(spc);
 51     return ;
 52 }
 53 void update(int l,int r,int ll,int rr,int spc,lnt v)
 54 {
 55     if(l>rr||ll>r)
 56         return ;
 57     if(ll<=l&&r<=rr)
 58     {
 59         add(spc,v);
 60         return ;
 61     }
 62     int mid=(l+r)>>1;
 63     pushdown(spc);
 64     update(l,mid,ll,rr,lll,v);
 65     update(mid+1,r,ll,rr,rrr,v);
 66     pushup(spc);
 67     return ;
 68 }
 69 lnt query(int l,int r,int ll,int rr,int spc)
 70 {
 71     if(l>rr||ll>r)
 72         return 0x3f3f3f3f;
 73     if(ll<=l&&r<=rr)
 74         return tr[spc].minv;
 75     int mid=(l+r)>>1;
 76     pushdown(spc);
 77     return std::min(query(l,mid,ll,rr,lll),query(mid+1,r,ll,rr,rrr));
 78 }
 79 int main()
 80 {
 81     scanf("%d%d",&n,&k);
 82     for(int i=2;i<=n;i++)
 83         scanf("%lld",&d[i]);
 84     for(int i=1;i<=n;i++)
 85         scanf("%lld",&c[i]);
 86     for(int i=1;i<=n;i++)
 87         scanf("%lld",&s[i]);
 88     for(int i=1;i<=n;i++)
 89         scanf("%lld",&w[i]);
 90     for(int i=1;i<=n;i++)
 91     {
 92         lp[i]=rp[i]=i;
 93         int l=1,r=i-1;
 94         while(l<=r)
 95         {
 96             int mid=(l+r)>>1;
 97             if(d[i]-d[mid]<=s[i])
 98             {
 99                 r=mid-1;
100                 lp[i]=mid;
101             }else
102                 l=mid+1;
103         }
104         l=i+1,r=n;
105         while(l<=r)
106         {
107             int mid=(l+r)>>1;
108             if(d[mid]-d[i]<=s[i])
109             {
110                 l=mid+1;
111                 rp[i]=mid;
112             }else
113                 r=mid-1;
114         }
115         lim[rp[i]].push_back(i);
116     }
117     lnt sum=0;
118     for(int i=1;i<=n;i++)
119     {
120         dp[i]=c[i]+sum;
121         for(int j=0;j<lim[i].size();j++)
122             sum+=w[lim[i][j]];
123     }
124     lnt ans=sum;
125     for(int i=1;i<=k;i++)
126     {
127         build(1,n,1);
128         for(int j=1;j<=n;j++)
129         {
130             dp[j]=query(1,n,1,j-1,1)+c[j];
131             for(int o=0;o<lim[j].size();o++)
132                 update(1,n,1,lp[lim[j][o]]-1,1,w[lim[j][o]]);
133         }
134         ans=std::min(ans,query(1,n,1,n,1));
135     }
136     printf("%lld\n",ans);
137     return 0;
138 }

 

posted @ 2019-01-01 20:04  Unstoppable728  阅读(187)  评论(0编辑  收藏  举报