返回

快读与线段树二分,一同斩获AcWing 796!

闲谈

AcWing 796 是一道经典的算法题,它要求你处理一个 n 行 m 列的整数矩阵,并执行 q 个操作。每个操作都包含五个整数 x1, y1, x2, y2, c,其中 (x1, y1) 和 (x2, y2) 表示一个子矩阵的左上角坐标和右下角坐标。 对于每个操作,你都需要将该子矩阵中所有元素的值都增加 c。

解决这个问题的方法有很多种,但最有效的一种方法是使用线段树。线段树是一种数据结构,它可以用来高效地更新和查询一个数组中的元素。

在我们的问题中,我们可以将每个元素都存储在一个线段树中。当我们要更新一个子矩阵中的元素时,我们只需要更新线段树中相应的部分即可。当我们要查询一个子矩阵中的元素时,我们只需要查询线段树中相应的部分即可。

使用线段树可以将问题的复杂度从 O(nmq) 降低到 O(log n log m q),其中 n 是矩阵的行数,m 是矩阵的列数,q 是操作的个数。

除了线段树之外,我们还可以使用一种叫做快读的技巧来提高代码的效率。快读是一种可以快速读取数据的技术,它可以将读取数据的速度提高到原来的几倍甚至几十倍。

使用快读可以将问题的复杂度从 O(nmq) 降低到 O(log n log m q + q),其中 n 是矩阵的行数,m 是矩阵的列数,q 是操作的个数。

如果你对线段树和快读还不熟悉,那么我建议你阅读一下相关的资料。网上有很多关于这两个主题的教程,你也可以在 AcWing 上找到一些相关的题目来练习。

相信你一定能学会这两种技巧,并用它们来解决 AcWing 796。加油!

现在,我们来看一下如何使用线段树和快读来解决 AcWing 796。

首先,我们需要定义一个线段树的类。这个类应该包含以下几个成员:

struct SegmentTree {
  vector<int> tree;
  int n;

  SegmentTree(int n) : tree(4 * n, 0), n(n) {}

  void update(int l, int r, int c, int node = 1, int start = 1, int end = n) {
    if (l > end || r < start) return;
    if (l <= start && r >= end) {
      tree[node] += c;
      return;
    }
    int mid = (start + end) / 2;
    update(l, r, c, 2 * node, start, mid);
    update(l, r, c, 2 * node + 1, mid + 1, end);
  }

  int query(int l, int r, int node = 1, int start = 1, int end = n) {
    if (l > end || r < start) return 0;
    if (l <= start && r >= end) return tree[node];
    int mid = (start + end) / 2;
    return query(l, r, 2 * node, start, mid) + query(l, r, 2 * node + 1, mid + 1, end);
  }
};

接下来,我们需要定义一个快读的类。这个类应该包含以下几个成员:

struct FastReader {
  FILE *fp;
  char *buf;
  int buf_size;
  int buf_pos;

  FastReader() {
    fp = stdin;
    buf_size = 1 << 16;
    buf = new char[buf_size];
    buf_pos = 0;
  }

  int readInt() {
    int c = read();
    while (c < '0' || c > '9') c = read();
    int x = 0;
    while (c >= '0' && c <= '9') {
      x = x * 10 + c - '0';
      c = read();
    }
    return x;
  }

private:
  int read() {
    if (buf_pos == buf_size) {
      buf_pos = 0;
      buf_size = fread(buf, 1, buf_size, fp);
      if (buf_size == 0) return EOF;
    }
    return buf[buf_pos++];
  }
};

最后,我们可以使用这两个类来解决 AcWing 796。

int main() {
  FastReader reader;
  int n = reader.readInt();
  int m = reader.readInt();
  int q = reader.readInt();
  SegmentTree tree(n * m);
  while (q--) {
    int x1 = reader.readInt();
    int y1 = reader.readInt();
    int x2 = reader.readInt();
    int y2 = reader.readInt();
    int c = reader.readInt();
    tree.update(x1, x2, c, 1, 1, n);
    tree.update(y1, y2, c, 1, 1, m);
  }
  int ans = tree.query(1, n, 1, 1, n);
  printf("%d\n", ans);
  return 0;
}

这段代码首先使用快读读取输入。然后,它使用线段树来更新和查询矩阵中的元素。最后,它输出矩阵中的最大元素。