1. 程式人生 > >luogu2605 基站選址 (線段樹優化dp)

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 }