[Segment tree optimization DP] [ZJOI2010] base site

Title Description

There are N villages located in a straight line, a distance between the first distance between the first villages i (i> 1) villages to Di. Need to build no more than the K communication base stations in these villages, the cost of establishing the base station in the i-th village-Ci. If the establishment of a communication station within a range not exceeding the distance between the first Si i villages, then covered by a base station village. If the i villages not covered, you will need to compensate them at a cost of Wi. The question now is, to select the location of the base station so as to minimize the total cost.

Input Format

The first line of the input file contains two integers N, K, meaning described above.

The second line contains the integers N-1, respectively, D2, D3, ..., DN, which number N-1 is incremented.

The third line contains N integers, denotes C1, C2, ... CN.

The fourth row contains N integers, indicates S1, S2, ..., SN.

The fifth line contains N integers, represents W1, W2, ..., WN.

Output Format

The output file contains only one integer representing the minimum total cost.

Sample input and output

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

Export

4

Description / Tips

40% of the data, N <= 500;

100% of the data, K <= N, K <= 100, N <= 20,000, Di <= 1000000000, Ci <= 10000, Si <= 1000000000, Wi <= 10000.

Solution

 

Consider the simple DP

f [i] [j] represents only consider before i villages and will build base stations in the village i, j has been building a base of minimum cost

This will ignore the effects of the last base station after the village

So we built a false infinity fake village station, no fees,

Not above drawbacks, max f [n] [1 - k] is the answer

 

Transfer equation f [i] [j] = min (f [k] [j-1] + cost [k] [i])    

              cost [k] [i] i and k is built in the base station, no compensation takes the intermediate built, is computable constant

 

j This dimension can roll out, we got the time complexity of O (n * n * k) of simple DP algorithm

 

Consider optimization, the minimum value obviously can maintain a segment tree

 

问题转化为如何计算cost[k][i]

考虑一个村庄何时可以获得赔偿  显然是枚举到向右距离超过si的村庄, 且用来转移的k距离超过si时
注意到这是一个区间加, 所以我们用邻接表存储这样的操作,时间复杂度O(k*nlogn)完了。。
 
总结 1、建虚点避免后效性,方便设状态
        2、线段树优化DP,要记住格式
  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 const int N=20005,inf=0x3f3f3f3f;
  5 int n,k,d[N],c[N],s[N],w[N],f[N];
  6 
  7 int num,last[N],nxt[N],ord[N];
  8 inline void add(int x,int hao){nxt[++num]=last[x]; last[x]=num; ord[num]=hao;}
  9 int st[N],ed[N];
 10 inline void pre()
 11  {for(int i=1;i<=n;i++)
 12    {st[i]=lower_bound(d+1,d+n+1,d[i]-s[i])-d;
 13     ed[i]=upper_bound(d+1,d+n+1,d[i]+s[i])-d-1;
 14     add(ed[i],i);
 15    } // 在往ed后就不能覆盖这些基站了,要考虑赔偿 
 16  }
 17  
 18  
 19 struct point{int l,r,minn,lazy;}t[4*N]; 
 20 
 21 
 22 inline void pushup(int i) {t[i].minn=min(t[2*i].minn,t[2*i+1].minn); } 
 23 
 24 inline void pass(int i,int x) {t[i].minn+=x; t[i].lazy+=x;}
 25 
 26 inline void pushdown(int i)
 27   {if(!t[i].lazy) return;
 28    pass(2*i,t[i].lazy); pass(2*i+1,t[i].lazy);
 29    t[i].lazy=0;
 30   }
 31   
 32   
 33   
 34 void build(int i,int l,int r)
 35   {t[i].l=l; t[i].r=r;  t[i].lazy=0;
 36   
 37    if(l==r) {t[i].minn=f[r]; return;}
 38    
 39    int mid=t[i].l+t[i].r>>1;
 40    build(2*i,l,mid); build(2*i+1,mid+1,r);
 41    
 42    pushup(i);
 43   }
 44 
 45 void add(int i,int l,int r,int x)
 46  {if(l>r) return;
 47   if(l<=t[i].l && t[i].r<=r) {pass(i,x); return;}
 48   
 49   int mid=t[i].l+t[i].r>>1; pushdown(i);
 50   
 51   if(l<=mid) add(2*i,l,r,x);
 52   if(mid<r)  add(2*i+1,l,r,x);
 53   
 54   pushup(i);
 55  } 
 56  
 57  
 58 int ask(int i,int l,int r)
 59  {if(l>r) return 0;
 60   if(l<=t[i].l && t[i].r<=r) return t[i].minn;
 61   int mid=t[i].l+t[i].r>>1; pushdown(i);
 62   
 63   if(r<=mid) return ask(2*i,l,r);
 64   if(mid<l)  return ask(2*i+1,l,r);
 65              return min(ask(2*i,l,r),ask(2*i+1,l,r));
 66   pushup(i);
 67  }
 68 inline void hehe()
 69  {
 70   int cmp=0;    
 71   //  手动处理只能选一个基站的边界DP值,相当于每次必须从f[0]=0转移 
 72   for(int i=1;i<=n;i++)    
 73    {f[i]=cmp+c[i];
 74     
 75     for(int j=last[i];j;j=nxt[j])cmp+=w[ord[j]];
 76    }
 77   int ans=f[n]; 
 78   for(int i=2;i<=k;i++)
 79    {build(1,1,n);
 80    
 81     for(int j=1;j<=n;j++)
 82      {if (i>j) f[j]=inf;
 83       else f[j]=ask(1,i-1,j-1)+c[j];
 84       
 85       for(int p=last[j];p;p=nxt[p])
 86         add(1,1,st[ord[p]]-1,w[ord[p]]);
 87         
 88      }
 89     ans=min(ans,f[n]); 
 90    }
 91   printf("%d",ans);     
 92  } 
 93 int main()
 94  {
 95  scanf("%d%d",&n,&k); k++;
 96  for(int i=2;i<=n;i++) scanf("%d",&d[i]);
 97  for(int i=1;i<=n;i++) scanf("%d",&c[i]);
 98  for(int i=1;i<=n;i++) scanf("%d",&s[i]);
 99  for(int i=1;i<=n;i++) scanf("%d",&w[i]);
100  n++; d[n]=w[n]=inf;  
101     //当我们推导i时,我们只考虑了它和前面的基站产生的影响
102     //这时对于最后一个基站我们不会考虑它和之后的村庄产生的影响
103     //则我们可以在最后增加一个村庄
104     //保证它必定被作为基站(无建设费用)且不对前面产生影响
105     //这样就不会有遗漏的了 
106  pre(); 
107  hehe();
108 return 0;
109  }

 

 

Guess you like

Origin www.cnblogs.com/YuXiaoze/p/11858630.html