luogu2605 基站选址 (线段树优化dp)

设f[i][j]表示在第i个村庄建第j个基站的花费

那么有$f[i][j]=min\{f[k][j-1]+w[k,i]\}$,其中w[k,i]表示在k,i建基站,k,i中间的不能被满足的村庄的赔偿金之和

如果把每个村庄能被满足的区间处理出来,记做$[l_i,r_i]$,那么i,j不能满足的村庄,就是$i<l,r<j$的村庄

考虑将$f[i][k]+w[i,j]$的i固定,而j随着dp进行而变化,这样维护K个线段树

那么当j越来越大,会有更多的村庄[l,r]变得满足r<j,被加入到线段树的区间[1,l-1]中

用堆来维护这些村庄,按r从大到小排序即可

复杂度$O(nklogn)$

  1 #include<bits/stdc++.h>
  2 #define pa pair<ll,ll>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 #define MP make_pair
  5 using namespace std;
  6 typedef long long ll;
  7 const int maxn=2e4+10,maxk=105;
  8 
  9 inline char gc(){
 10     return getchar();
 11     static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
 12     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
 13 }
 14 inline ll rd(){
 15     ll x=0;char c=gc();bool neg=0;
 16     while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
 17     while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
 18     return neg?(~x+1):x;
 19 }
 20 
 21 int N,K,f[maxn][maxk],pos[maxn],cost[maxn];
 22 struct Node{
 23     int l,r,w;
 24 }p[maxn];
 25 int mi[maxk*maxn*2],laz[maxk*maxn*2],ch[maxk*maxn*2][2],rt[maxk],pct;
 26 inline bool operator < (Node a,Node b){return a.r>b.r;}
 27 priority_queue<Node> q;
 28 
 29 inline void tag(int p,int v){
 30     mi[p]+=v,laz[p]+=v;
 31 }
 32 
 33 inline void pushdown(int p){
 34     if(!laz[p]) return;
 35     int a=ch[p][0],b=ch[p][1];
 36     if(a) tag(a,laz[p]);
 37     if(b) tag(b,laz[p]);
 38     laz[p]=0;
 39 }
 40 inline void update(int p){
 41     mi[p]=min(mi[ch[p][0]],mi[ch[p][1]]);
 42 }
 43 
 44 inline void add(int p,int l,int r,int x,int y,int z){
 45     if(x<=l&&r<=y) tag(p,z);
 46     else{
 47         pushdown(p);int m=l+r>>1;
 48         if(x<=m) add(ch[p][0],l,m,x,y,z);
 49         if(y>=m+1) add(ch[p][1],m+1,r,x,y,z);
 50         update(p);
 51     }
 52 }
 53 
 54 inline int query(int p,int l,int r,int x,int y){
 55     if(x<=l&&r<=y) return mi[p];
 56     int m=l+r>>1;pushdown(p);int re=1e9;
 57     if(x<=m) re=query(ch[p][0],l,m,x,y);
 58     if(y>=m+1) re=min(re,query(ch[p][1],m+1,r,x,y));
 59     return re;
 60 }
 61 
 62 inline void change(int p,int l,int r,int x,int y){
 63     if(l==r) mi[p]=y;
 64     else{
 65         int m=l+r>>1;pushdown(p);
 66         if(x<=m) change(ch[p][0],l,m,x,y);
 67         else change(ch[p][1],m+1,r,x,y);
 68         update(p);
 69     }
 70 }
 71 
 72 inline void build(int &p,int l,int r){
 73     p=++pct;mi[p]=1e9+233;
 74     if(l<r){
 75         int m=l+r>>1;
 76         build(ch[p][0],l,m);build(ch[p][1],m+1,r);
 77     }
 78 }
 79 
 80 int main(){
 81     //freopen("","r",stdin);
 82     int i,j,k;
 83     N=rd(),K=rd();
 84     for(i=2;i<=N;i++)
 85         pos[i]=rd();
 86     for(i=1;i<=N;i++)
 87         cost[i]=rd();
 88     pos[N+1]=1e9+1;
 89     for(i=1;i<=N;i++){
 90         int s=rd();
 91         p[i].l=lower_bound(pos+1,pos+N+1,pos[i]-s)-pos;
 92         p[i].r=upper_bound(pos+1,pos+N+1,pos[i]+s)-pos-1;
 93     }
 94     for(i=1;i<=N;i++)
 95         p[i].w=rd();
 96     p[N+1].l=N+1,p[N+1].r=N+1,p[N+1].w=233333333,N++,K++;
 97     CLR(f,127);f[0][0]=0;
 98     for(i=1;i<=K;i++) build(rt[i],1,N);
 99     for(i=1;i<=N;i++){
100         while(!q.empty()){
101             Node p=q.top();
102             if(p.r>=i) break;
103             q.pop();f[0][0]+=p.w;
104             for(k=1;k<=min(p.l-1,K);k++)
105                 add(rt[k],1,N,1,p.l-1,p.w);
106         }
107         f[i][1]=f[0][0]+cost[i];change(rt[1],1,N,i,f[i][1]);
108         for(k=2;k<=min(i,K);k++){
109             f[i][k]=query(rt[k-1],1,N,1,i-1)+cost[i];
110             change(rt[k],1,N,i,f[i][k]);
111         }
112         q.push(p[i]);
113     }
114     int ans=2e9;
115     for(i=1;i<=K;i++) ans=min(ans,f[N][i]);
116     printf("%d\n",ans);
117     return 0;
118 }

 

posted @ 2018-12-01 18:56  Ressed  阅读(239)  评论(0编辑  收藏  举报