zoukankan      html  css  js  c++  java
  • [bzoj3343]教主的魔法——分块

    Brief description

    给定一个数列,您需要支持一下两种操作:

    1. 给[l,r]同加一个数
    2. 询问[l,r]中有多少数字大于或等于v

    Algorithm analyse

    这个题一时想不到什么有效的数据结构,但是暴力法非常好想:一个(Theta(n))的暴力算法。
    我们考虑分块做,不那么暴力。
    把数据分为(sqrt n)一份,那么对于每一个查询,我们都可以把这个查询分为(sqrt n)个区间,修改的时候也是(Theta(sqrt n))的级别,所以总的复杂度就是(Theta(sqrt nlogsqrt n))
    具体地,对于每一块,我们都存储排序前和排序后的序列,这样我们就解决了这个题。
    对于size的大小,我解了一个方程,跑到了2052ms,bzoj17名,已经是这个解法(不使用平衡树)的极限了,还是非常满意。

    顺便%%%强校XMYZ

    Code

    #include <algorithm>
    #include <cctype>
    #include <cmath>
    #include <cstdio>
    int n, q, m, block;
    const int maxn = 1000001;
    int a[maxn], b[maxn], pos[maxn], add[maxn];
    using std::sort;
    using std::min;
    inline int read() {
      int x = 0, f = 1;
      char ch = getchar();
      while (!isdigit(ch)) {
        if (ch == '-')
          f = -1;
        ch = getchar();
      }
      while (isdigit(ch)) {
        x = x * 10 + ch - '0';
        ch = getchar();
      }
      return x * f;
    }
    inline void reset(int x) {
      int l = (x - 1) * block + 1, r = min(x * block, n);
      for (int i = l; i <= r; i++)
        b[i] = a[i];
      sort(b + l, b + r + 1);
    }
    inline int find(int x, int v) {
      int l = (x - 1) * block + 1, r = min(x * block, n);
      int last = r;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (b[mid] < v)
          l = mid + 1;
        else
          r = mid - 1;
      }
      return last - l + 1;
    }
    inline void update(int x, int y, int v) {
      if (pos[x] == pos[y]) {
        for (int i = x; i <= y; i++)
          a[i] = a[i] + v;
      } else {
        for (int i = x; i <= pos[x] * block; i++)
          a[i] = a[i] + v;
        for (int i = (pos[y] - 1) * block + 1; i <= y; i++)
          a[i] = a[i] + v;
      }
      reset(pos[x]);
      reset(pos[y]);
      for (int i = pos[x] + 1; i < pos[y]; i++)
        add[i] += v;
    }
    inline int query(int x, int y, int v) {
      int sum = 0;
      if (pos[x] == pos[y]) {
        for (int i = x; i <= y; i++)
          if (a[i] + add[pos[i]] >= v)
            sum++;
      } else {
        for (int i = x; i <= pos[x] * block; i++)
          if (a[i] + add[pos[i]] >= v)
            sum++;
        for (int i = (pos[y] - 1) * block + 1; i <= y; i++)
          if (a[i] + add[pos[i]] >= v)
            sum++;
        for (int i = pos[x] + 1; i < pos[y]; i++)
          sum += find(i, v - add[i]);
      }
      return sum;
    }
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("input", "r", stdin);
    #endif
      n = read(), q = read();
      if (n >= 500000)
        block = 3676;
      else if (n >= 5000) {
        block = 209;
      } else
        block = int(sqrt(n));
      for (int i = 1; i <= n; i++) {
        a[i] = read();
        pos[i] = (i - 1) / block + 1;
        b[i] = a[i];
      }
      if (n % block)
        m = n / block + 1;
      else
        m = n / block;
      for (int i = 1; i <= m; i++)
        reset(i);
      for (int i = 1; i <= q; i++) {
        char ch[5];
        int x, y, v;
        scanf("%s", ch);
        x = read(), y = read(), v = read();
        if (ch[0] == 'M')
          update(x, y, v);
        else
          printf("%d
    ", query(x, y, v));
      }
    }
    
  • 相关阅读:
    团队冲刺第二阶段-7
    用户体验评价
    团队冲刺第二阶段-6
    第十四周学习进度报告
    团队冲刺第二阶段-5
    团队冲刺第二阶段-4
    14周课堂测试---找水王
    进度日报14
    进度日报13
    进度日报12
  • 原文地址:https://www.cnblogs.com/gengchen/p/6501976.html
Copyright © 2011-2022 走看看