zoukankan      html  css  js  c++  java
  • 块状数组

    num = sqrt(n);
    for (int i = 1; i <= num; i++)
      st[i] = n / num * (i - 1) + 1, ed[i] = n / num * i;
    ed[num] = n;
    for (int i = 1; i <= num; i++) {
      for (int j = st[i]; j <= ed[i]; j++) {
        belong[j] = i;
      }
      size[i] = ed[i] - st[i] + 1;
    }

    块状数组,即把一个数组分为几个块,块内信息整体保存,若查询时遇到两边不完整的块直接暴力查询。一般情况下,块的长度为√n 

    其中 st[i] 和 ed[i] 为块的起点和终点,size[i] 为块的大小。

    保存与修改块内信息

    两种操作:

    1. 区间 x y 每个数都加上 z
    2. 查询区间 x y  内大于等于 z 的数的个数.

    我们要询问一个块内大于等于一个数的数的个数,所以需要一个 t 数组对块内排序,a 为原来的(未被排序的)数组。对于整块的修改,使用类似于标记永久化的方式,用 dlt 保存现在块内整体加上的值。设  为查询和修改的操作次数总和,则时间复杂度 

    void Sort(int k) {
      for (int i = st[k]; i <= ed[k]; i++) t[i] = a[i];
      sort(t + st[k], t + ed[k] + 1);
    }
    void Modify(int l, int r, int c) {
      int x = belong[l], y = belong[r];
      if (x == y)  // 区间在一个块内就直接修改
      {
        for (int i = l; i <= r; i++) a[i] += c;
        Sort(x);
        return;
      }
      for (int i = l; i <= ed[x]; i++) a[i] += c;   // 直接修改起始段
      for (int i = st[y]; i <= r; i++) a[i] += c;   // 直接修改结束段
      for (int i = x + 1; i < y; i++) dlt[i] += c;  // 中间的整块打上标记
      Sort(x);
      Sort(y);
    }
    int Answer(int l, int r, int c) {
      int ans = 0, x = belong[l], y = belong[r];
      if (x == y) {
        for (int i = l; i <= r; i++)
          if (a[i] + dlt[x] >= c) ans++;
        return ans;
      }
      for (int i = l; i <= ed[x]; i++)
        if (a[i] + dlt[x] >= c) ans++;
      for (int i = st[y]; i <= r; i++)
        if (a[i] + dlt[y] >= c) ans++;
      for (int i = x + 1; i <= y - 1; i++)
        ans += ed[i] - (lower_bound(t + st[i], t + ed[i] + 1, c - dlt[i]) - t) + 1;
      // 用 lower_bound 找出中间每一个整块中第一个大于等于 c 的数的位置
      return ans;
    }

    两种操作:

    1. 区间 x y  每个数都变成 z
    2. 查询区间x y 内小于等于  z的数的个数。

    用 dlt 保存现在块内是否被整体赋值了。用一个值表示没有。对于边角块,查询前要 pushdown,把块内存的信息下放到每一个数上。赋值之后记得重新 sort 一遍。其他方面同上题。

    void Sort(int k) {
      for (int i = st[k]; i <= ed[k]; i++) t[i] = a[i];
      sort(t + st[k], t + ed[k] + 1);
    }
    void PushDown(int x) {
      if (dlt[x] != 0x3f3f3f3f3f3f3f3fll)  // 用该值标记块内没有被整体赋值
        for (int i = st[x]; i <= ed[x]; i++) a[i] = t[i] = dlt[x];
      dlt[x] = 0x3f3f3f3f3f3f3f3fll;
    }
    void Modify(int l, int r, int c) {
      int x = belong[l], y = belong[r];
      PushDown(x);
      if (x == y) {
        for (int i = l; i <= r; i++) a[i] = c;
        Sort(x);
        return;
      }
      PushDown(y);
      for (int i = l; i <= ed[x]; i++) a[i] = c;
      for (int i = st[y]; i <= r; i++) a[i] = c;
      Sort(x);
      Sort(y);
      for (int i = x + 1; i < y; i++) dlt[i] = c;
    }
    int Binary_Search(int l, int r, int c) {
      int ans = l - 1, mid;
      while (l <= r) {
        mid = (l + r) / 2;
        if (t[mid] <= c)
          ans = mid, l = mid + 1;
        else
          r = mid - 1;
      }
      return ans;
    }
    int Answer(int l, int r, int c) {
      int ans = 0, x = belong[l], y = belong[r];
      PushDown(x);
      if (x == y) {
        for (int i = l; i <= r; i++)
          if (a[i] <= c) ans++;
        return ans;
      }
      PushDown(y);
      for (int i = l; i <= ed[x]; i++)
        if (a[i] <= c) ans++;
      for (int i = st[y]; i <= r; i++)
        if (a[i] <= c) ans++;
      for (int i = x + 1; i <= y - 1; i++) {
        if (0x3f3f3f3f3f3f3f3fll == dlt[i])
          ans += Binary_Search(st[i], ed[i], c) - st[i] + 1;
        else if (dlt[i] <= c)
          ans += size[i];
      }
      return ans;
    }
    rush!
  • 相关阅读:
    使用VisualStudio2015开发QT项目
    界面控件
    SmartGit 试用过期
    视图和模型变换
    模型变换和视图变换
    一元二次方程
    论cudnn与cuda之间的关系,和实际例子测试。
    在Ubuntu 18.04上安装Tensorflow
    ubuntu14.04安装CUDA8.0
    Windows10系统远程桌面连接出现卡顿如何解决
  • 原文地址:https://www.cnblogs.com/LH2000/p/15501120.html
Copyright © 2011-2022 走看看