zoukankan      html  css  js  c++  java
  • bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)

    【题目链接】

        http://www.lydsy.com/JudgeOnline/problem.php?id=1835

    【题意】

        有n个村庄,每个村庄位于d[i],要求建立不多于k个基站,在第i个村庄建基站的费用为c[i],如果在距离村i不超过s[i]内有基站则该村被覆盖,村i不被覆盖的补偿费为w[i],求最少花费。

    【思路】

        设f[i][j]表示第i个村建第j个基站的最小花费,则有转移式:

            f[i][j]=min{ f[k][j-1]+cost(k,i) } + c[i] ,j-1<=k<=i-1

            cost(k,i)=sigma{ w[x] } k+1<=x<=i-1 , 且x未被覆盖

        f[][]需要求一个区间最小值,我们尝试用线段树维护每一层的这个值。

        枚举j,考虑每一层i。

        我们设st[i],ed[i]分别表示在i左右距离i最远的st[i],ed[i]建基站依旧可以覆盖到i,假设我们已经求完了f[i][j]要求f[i+1][j],考虑那些恰可以被i覆盖到而不能被i+1覆盖到的,即满足ed[x]=i的点,将[1..st[x]-1]区间内的线段树值都加w[x],意为前一个基站k位于[1..st[x]-1]那么点x因不会被覆盖到需要做出赔偿。求f[i]的时候查询区间[1..i-1]内线段树值的最小即可。

        其中st[i],ed[i]可以用二分法求。

        线段树提供区间操作区间查询的操作。

        总的时间复杂度为O(nmlogn)

        辣鸡线段树,毁我青春(连个线段树都不会写了T^T

    【代码】

      1 #include<set>
      2 #include<cmath>
      3 #include<queue>
      4 #include<vector>
      5 #include<cstdio>
      6 #include<cstring>
      7 #include<iostream>
      8 #include<algorithm>
      9 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
     10 using namespace std;
     11 
     12 typedef long long ll;
     13 const int N = 1e5+10;
     14 const int inf = 1e9;
     15 
     16 ll read() {
     17     char c=getchar();
     18     ll f=1,x=0;
     19     while(!isdigit(c)) {
     20         if(c=='-') f=-1; c=getchar();
     21     }
     22     while(isdigit(c))
     23         x=x*10+c-'0',c=getchar();
     24     return x*f;
     25 }
     26 
     27 int n,K; ll f[N];
     28 ll d[N],c[N],s[N],w[N],st[N],ed[N];
     29 vector<ll> ep[N];
     30 
     31 struct Tnode {
     32     int l,r; ll v,tag;
     33 }T[N<<1];
     34 
     35 void pushdown(int u)
     36 {
     37     if(T[u].l==T[u].r||(!T[u].tag)) return ;
     38     ll& t=T[u].tag;
     39     T[u<<1].v+=t,T[u<<1].tag+=t;
     40     T[u<<1|1].v+=t,T[u<<1|1].tag+=t;
     41     t=0;
     42 }
     43 void maintain(int u) 
     44 {
     45     T[u].v=min(T[u<<1].v,T[u<<1|1].v);
     46 }
     47 void build(int u,int l,int r)
     48 {
     49     T[u].l=l,T[u].r=r;
     50     T[u].tag=0;
     51     if(l==r) T[u].v=f[l];
     52     else {
     53         int mid=l+r>>1;
     54         build(u<<1,l,mid);
     55         build(u<<1|1,mid+1,r);
     56         maintain(u);
     57     }
     58 }
     59 void Add(int u,int L,int R,ll x)
     60 {
     61     if(L>R) return ;                    //处理 L>R 
     62     pushdown(u);
     63     if(L<=T[u].l&&T[u].r<=R) 
     64         T[u].v+=x,T[u].tag+=x;
     65     else {
     66         int mid=T[u].l+T[u].r>>1;
     67         if(L<=mid) Add(u<<1,L,R,x);
     68         if(mid<R) Add(u<<1|1,L,R,x);
     69         maintain(u);
     70     }
     71 }
     72 ll query(int u,int L,int R) 
     73 {
     74     if(L>R) return 0;
     75     pushdown(u);
     76     if(L<=T[u].l&&T[u].r<=R) return T[u].v;
     77     else {
     78         int mid=T[u].l+T[u].r>>1; ll ans=inf;
     79         if(L<=mid) ans=min(ans,query(u<<1,L,R));
     80         if(mid<R) ans=min(ans,query(u<<1|1,L,R));
     81         return ans;
     82     }
     83 }
     84 
     85 //lower_bound定义为找到第一个不小于v的数的指针 
     86 void init()
     87 {
     88     n=read(),K=read();
     89     FOR(i,2,n) d[i]=read();
     90     FOR(i,1,n) c[i]=read();
     91     FOR(i,1,n) s[i]=read();
     92     FOR(i,1,n) w[i]=read();
     93     n++,K++;
     94     d[n]=inf; w[n]=inf;
     95     FOR(i,1,n) {
     96         int l=d[i]-s[i],r=d[i]+s[i];
     97         l=lower_bound(d+1,d+n+1,l)-d;
     98         r=lower_bound(d+1,d+n+1,r)-d;
     99         if(d[i]+s[i]<d[r]) r--;
    100         st[i]=l,ed[i]=r;
    101         ep[ed[i]].push_back(i);
    102     }
    103 }
    104 ll dp()
    105 {
    106     ll ans,tmp=0;
    107     FOR(i,1,n) {
    108         f[i]=tmp+c[i];
    109         FOR(j,0,(int)ep[i].size()-1)
    110             tmp+=w[ep[i][j]];
    111     }
    112     ans=f[n];
    113     FOR(j,2,K) {
    114         build(1,1,n);
    115         FOR(i,1,n) {
    116             f[i]=query(1,1,i-1)+c[i];
    117             FOR(k,0,(int)ep[i].size()-1) {
    118                 int x=ep[i][k];
    119                 Add(1,1,st[x]-1,w[x]);
    120             }
    121         }
    122         ans=min(ans,f[n]);
    123     }
    124     return ans;
    125 }
    126 
    127 int main()
    128 { 
    129     //freopen("in.in","r",stdin);
    130     //freopen("out.out","w",stdout);
    131     init();
    132     printf("%lld",dp());
    133     return 0;
    134 }
  • 相关阅读:
    fjnu2019第二次友谊赛 B题
    2019年FJNU低编赛 G题(dfs博弈)
    洛谷P2634 聪聪可可 (点分治)
    洛谷P3128 [USACO15DEC]最大流Max Flow (树上差分)
    Comet OJ
    Comet OJ
    Comet OJ
    Comet OJ
    Django models操作、中间件、缓存、信号、分页
    Ajax
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5288660.html
Copyright © 2011-2022 走看看