zoukankan      html  css  js  c++  java
  • 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


    思路

    首先一个思路是前i个节点放j个基站

    为了方便转移,强制第i个节点上一定会放上一个基站

    然后怎么办?

    有一个转移是(dp_{i,k}=dp_{j,k}+calc(j+1,i-1)+c_i)

    然后考虑怎么快速计算对于每个i的(dp_{j,k}+calc(j+1,i-1))

    我们令每一个节点可以覆盖到它的基站位置是([pre_i,nxt_i])

    那么(calc(j+1,i-1)=sum_{p=j+1}^{i-1}[pre_i>j&&nxt_i<i]w_i)

    如果把i向右平移,发现受影响的新增节点只有(nxt_t=i)的所有节点

    那么就按照(nxt_t)排序,每次因为我们维护所有的(dp_{j,k}+calc(j+1,i-1))

    所以对于所有([1,pre_t-1])的dp值全部要加上(w_t)

    然后就用线段树维护一下就可以了

    注意当k是0的时候初值的处理

    然后应该没什么大问题了


    是我傻逼写错了线段树。。


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    typedef pair<int, int> pi;
    typedef long long ll;
    typedef double db;
    #define fi first
    #define se second
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x;
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 1e5 + 10;
    int n, k, c[N], d[N], s[N], w[N];
    int dp[2][N];
    struct Node {
      int pre, nxt, id;
    } p[N];
    
    bool operator < (const Node a, const Node b) {
      return a.nxt < b.nxt;
    }
    
    #define LD (t << 1)
    #define RD (t << 1 | 1)
    int val[N << 2], tag[N << 2];
    
    void pushnow(int t, int vl) {
      val[t] += vl;
      tag[t] += vl;
    }
    
    void pushup(int t) {
      val[t] = min(val[LD], val[RD]);
    }
    
    void pushdown(int t) {
      if (tag[t]) {
        pushnow(LD, tag[t]);
        pushnow(RD, tag[t]);
        tag[t] = 0;
      }
    }
    
    void build(int t, int l, int r) {
      tag[t] = 0;
      val[t] = INF_of_int;
      if (l == r) return;
      int mid = (l + r) >> 1;
      build(LD, l, mid);
      build(RD, mid + 1, r);
    }
    
    void modify(int t, int l, int r, int pos, int vl) {
      if (l == r) {
        val[t] = vl;
        return;
      }
      pushdown(t);
      int mid = (l + r) >> 1;
      if (pos <= mid) modify(LD, l, mid, pos, vl);
      else modify(RD, mid + 1, r, pos, vl);
      pushup(t);
    }
    
    void modify(int t, int l, int r, int ql, int qr, int vl) {
      if (ql > qr) return;
      if (ql <= l && r <= qr) {
        pushnow(t, vl);
        return;
      }
      int mid = (l + r) >> 1;
      pushdown(t);
      if (qr <= mid) modify(LD, l, mid, ql, qr, vl);
      else if (ql > mid) modify(RD, mid + 1, r, ql, qr, vl);
      else {
        modify(LD, l, mid, ql, mid, vl);
        modify(RD, mid + 1, r, mid + 1, qr, vl);
      }
      pushup(t);
    }
    
    int find_pre(int x) {
      int l = 1, r = x, res = 0;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (s[x] >= d[x] - d[mid]) res = mid, r = mid - 1;
        else l = mid + 1;
      }
      return res;
    }
    
    int find_nxt(int x) {
      int l = x, r = n, res = 0;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (s[x] >= d[mid] - d[x]) res = mid, l = mid + 1;
        else r = mid - 1;
      }
      return res;
    }
    
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
      freopen("output.txt", "w", stdout);
    #endif
      memset(dp, 0, sizeof(dp));
      Read(n), Read(k);
      fu(i, 2, n) Read(d[i]);
      fu(i, 1, n) Read(c[i]);
      fu(i, 1, n) Read(s[i]);
      fu(i, 1, n) Read(w[i]);
      fu(i, 1, n) {
        p[i].pre = find_pre(i);
        p[i].nxt = find_nxt(i);
        p[i].id = i;
      }
      sort(p + 1, p + n + 1);
      int ans = INF_of_int, now = 1, sumw = 0;
      int ind = 0;
      fu(i, 1, n) {
        dp[ind][i] = sumw + c[i];
        while (now <= n && p[now].nxt <= i)
          sumw += w[p[now].id], ++now;
      }
      fu(j, 2, k + 1) {
        build(1, 1, n);
        ind ^= 1, now = 1;
        fu(i, 1, n) {
          dp[ind][i] = val[1] + c[i];
          while (now <= n && p[now].nxt <= i) 
            modify(1, 1, n, 1, p[now].pre - 1, w[p[now].id]), ++now;
          modify(1, 1, n, i, dp[ind ^ 1][i]);
        }
        ans = min(ans, val[1]);
      }
      Write(ans);
      return 0;
    }
    
  • 相关阅读:
    关于运行SWT程序遇到的一个错误的总结
    Window7英文系统中出现的中文乱码的更改设置
    关于SWT中的表格(TableViewer类)
    关于SWT的容器类之----面板Composite类和Group类
    关于SWT中的Combo类和List类
    js怎么获取图片的相对地址
    .NET/MVC-ViewBag、ViewData、TempData区别
    Razor语法(五)
    Razor语法(四)
    Razor语法(三)
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9910302.html
Copyright © 2011-2022 走看看