【题目链接】
【思路要点】
- 对于一个 t t t ,将 1 , 2 , 3 , . . . , t 1,2,3,...,t 1,2,3,...,t 所在方格染黑,剩余方格染白,考虑网格图中所有的 2 ∗ 2 2*2 2∗2 的正方形,那么 1 , 2 , 3 , . . . , t 1,2,3,...,t 1,2,3,...,t 形成一个矩形的充要条件为:
1 1 1 、包含 1 1 1 个黑色方格 2 ∗ 2 2*2 2∗2 的正方形恰好有 4 4 4 个。
2 2 2 、不存在包含 3 3 3 个黑色方格 2 ∗ 2 2*2 2∗2 的正方形。- 同时,当网格图中存在黑色方格时,包含 1 1 1 个黑色方格 2 ∗ 2 2*2 2∗2 的正方形至少有 4 4 4 个,因此,我们只需要用线段树维护所有 t t t 对应的包含 1 / 3 1/3 1/3 个黑色方格 2 ∗ 2 2*2 2∗2 的正方形的个数,并维护区间最小值的个数即可。
- 时间复杂度 O ( H W + Q L o g H W ) O(HW+QLogHW) O(HW+QLogHW) 。
【代码】
#include "seats.h" #include<bits/stdc++.h> using namespace std; const int MAXN = 1e6 + 5; int n, m, x[MAXN], y[MAXN]; vector <int> a[MAXN]; struct info {int one, tri; }; bool operator < (info a, info b) { if (a.one == b.one) return a.tri < b.tri; else return a.one < b.one; } info operator + (info a, info b) { return (info) {a.one + b.one, a.tri + b.tri}; } bool operator == (info a, info b) { return a.one == b.one && a.tri == b.tri; } bool valid(info a) { return a.one == 4 && a.tri == 0; } struct SegmentTree { struct Node { int lc, rc, cnt; info Min, tag; } a[MAXN * 2]; int n, size, root; void update(int root) { a[root].Min = min(a[a[root].lc].Min, a[a[root].rc].Min), a[root].cnt = 0; if (a[root].Min == a[a[root].lc].Min) a[root].cnt += a[a[root].lc].cnt; if (a[root].Min == a[a[root].rc].Min) a[root].cnt += a[a[root].rc].cnt; } void build(int &root, int l, int r, int *one, int *tri) { root = ++size; if (l == r) { a[root].Min = (info) {one[l], tri[l]}; a[root].cnt = 1; return; } int mid = (l + r) / 2; build(a[root].lc, l, mid, one, tri); build(a[root].rc, mid + 1, r, one, tri); update(root); } void init(int x, int *one, int *tri) { n = x; root = size = 0; build(root, 1, n, one, tri); } void pushdown(int root) { info tmp = a[root].tag; a[a[root].lc].tag = a[a[root].lc].tag + tmp; a[a[root].lc].Min = a[a[root].lc].Min + tmp; a[a[root].rc].tag = a[a[root].rc].tag + tmp; a[a[root].rc].Min = a[a[root].rc].Min + tmp; a[root].tag = (info) {0, 0}; } void modify(int root, int l, int r, int ql, int qr, info d) { if (l == ql && r == qr) { a[root].tag = a[root].tag + d; a[root].Min = a[root].Min + d; return; } pushdown(root); int mid = (l + r) / 2; if (mid >= ql) modify(a[root].lc, l, mid, ql, min(qr, mid), d); if (mid + 1 <= qr) modify(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, d); update(root); } void modify(int l, int r, info d) { if (l > r) return; else modify(root, 1, n, l, r, d); } int query() { if (valid(a[root].Min)) return a[root].cnt; else return 0; } } ST; int tri[MAXN], one[MAXN]; void give_initial_chart(int H, int W, vector <int> R, vector <int> C) { n = H, m = W; for (int i = 0; i <= n + 1; i++) { a[i].resize(m + 2); for (int j = 0; j <= m + 1; j++) a[i][j] = n * m + 1; } for (int i = 1; i <= n * m; i++) { x[i] = R[i - 1] + 1; y[i] = C[i - 1] + 1; a[x[i]][y[i]] = i; } for (int i = 0; i <= n; i++) for (int j = 0; j <= m; j++) { int tmp[4] = {a[i][j], a[i + 1][j], a[i][j + 1], a[i + 1][j + 1]}; sort(tmp, tmp + 4); one[tmp[0]]++, one[tmp[1]]--; tri[tmp[2]]++, tri[tmp[3]]--; } for (int i = 1; i <= n * m; i++) { one[i] += one[i - 1]; tri[i] += tri[i - 1]; } ST.init(n * m, one, tri); } void update(int x, int y, int f) { int tmp[4] = {a[x][y], a[x + 1][y], a[x][y + 1], a[x + 1][y + 1]}; sort(tmp, tmp + 4); ST.modify(tmp[0], tmp[1] - 1, (info) {f, 0}); ST.modify(tmp[2], tmp[3] - 1, (info) {0, f}); } void modify(int x, int y, int val) { update(x - 1, y - 1, -1); update(x, y - 1, -1); update(x - 1, y, -1); update(x, y, -1); a[x][y] = val; update(x - 1, y - 1, 1); update(x, y - 1, 1); update(x - 1, y, 1); update(x, y, 1); } int swap_seats(int p, int q) { p++, q++; int val = a[x[p]][y[p]], vbl = a[x[q]][y[q]]; swap(x[p], x[q]); swap(y[p], y[q]); modify(x[p], y[p], val); modify(x[q], y[q], vbl); return ST.query(); }