【思路要点】
- 用十字链表维护整个矩阵,操作时将被操作的子矩形提取出来,改变周围一圈点的连边,再拼接回去即可,单次操作修改的边数是 O ( N + M ) O(N+M) O(N+M) 的。
- 具体而言,一种可行的实现方式是在矩形周围增设一圈点作为哨兵节点,这些节点将不能被修改,用于提取子矩形。每个点记录其左右两个点的集合 { l , r } \{l,r\} {l,r} 和上下两个点的集合 { u , d } \{u,d\} {u,d} ,在翻转时,一个中间点的 r r r 和 l l l 可能会互换,但集合 { l , r } \{l,r\} {l,r} 是不变的。
- 这样的存储方式在想要访问 i . r i.r i.r 的时候需要同时知道 i . l i.l i.l 和 i i i , i . r i.r i.r 即为集合 { l , r } \{l,r\} {l,r} 中不是 i . l i.l i.l 的一个元素,这也是为什么我们需要一圈哨兵节点来提取子矩形的原因。
- 时间复杂度 O ( N M + Q ∗ ( N + M ) ) O(NM+Q*(N+M)) O(NM+Q∗(N+M)) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e3 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct info {int l, r, u, d; }; int n, m, q, tot, b[MAXN][MAXN], tmp[MAXN][MAXN], old[MAXN][MAXN]; int from[MAXN * MAXN], to[MAXN * MAXN]; info a[MAXN * MAXN]; void getr(int pos, int r) { if (pos == 0 || pos == n + 1) { for (int i = 1; i <= m; i++) tmp[pos][i] = old[pos][i] = b[pos][i]; return; } for (int i = 0, now = b[pos][0], last = 0; i <= r; i++) { tmp[pos][i] = old[pos][i] = now; int dest; if (a[now].r == last) dest = a[now].l; else dest = a[now].r; last = now, now = dest; } } void getc(int pos, int r) { if (pos == 0 || pos == m + 1) { for (int i = 1; i <= n; i++) tmp[i][pos] = old[i][pos] = b[i][pos]; return; } for (int i = 0, now = b[0][pos], last = 0; i <= r; i++) { tmp[i][pos] = old[i][pos] = now; int dest; if (a[now].d == last) dest = a[now].u; else dest = a[now].d; last = now, now = dest; } } void access(int xl, int yl, int xr, int yr) { getr(xl - 1, yr), getr(xl, yr); getr(xr + 1, yr), getr(xr, yr); getc(yl - 1, xr), getc(yl, xr); getc(yr + 1, xr), getc(yr, xr); } void modify(int pos, int from, int to) { a[pos].u = ((a[pos].u == from) ? (to) : (a[pos].u)); a[pos].d = ((a[pos].d == from) ? (to) : (a[pos].d)); a[pos].l = ((a[pos].l == from) ? (to) : (a[pos].l)); a[pos].r = ((a[pos].r == from) ? (to) : (a[pos].r)); } void makeup(int xl, int yl, int xr, int yr) { for (int i = xl; i <= xr; i++) { modify(tmp[i][yl - 1], from[tmp[i][yl - 1]], to[tmp[i][yl - 1]]); modify(tmp[i][yr + 1], from[tmp[i][yr + 1]], to[tmp[i][yr + 1]]); } for (int i = yl; i <= yr; i++) { modify(tmp[xl - 1][i], from[tmp[xl - 1][i]], to[tmp[xl - 1][i]]); modify(tmp[xr + 1][i], from[tmp[xr + 1][i]], to[tmp[xr + 1][i]]); } for (int i = yl; i <= yr; i++) { int pos = tmp[xl][i]; if (tmp[xl][i] == tmp[xr][i]) { if (a[pos].u == tmp[xl - 1][i] && a[pos].d == tmp[xr + 1][i]) continue; if (a[pos].d == tmp[xl - 1][i] && a[pos].u == tmp[xr + 1][i]) continue; } if (a[pos].u == old[xl - 1][i]) a[pos].u = tmp[xl - 1][i]; if (a[pos].d == old[xl - 1][i]) a[pos].d = tmp[xl - 1][i]; pos = tmp[xr][i]; if (a[pos].u == old[xr + 1][i]) a[pos].u = tmp[xr + 1][i]; if (a[pos].d == old[xr + 1][i]) a[pos].d = tmp[xr + 1][i]; } for (int i = xl; i <= xr; i++) { int pos = tmp[i][yl]; if (tmp[i][yl] == tmp[i][yr]) { if (a[pos].l == tmp[i][yl - 1] && a[pos].r == tmp[i][yr + 1]) continue; if (a[pos].r == tmp[i][yl - 1] && a[pos].l == tmp[i][yr + 1]) continue; } if (a[pos].l == old[i][yl - 1]) a[pos].l = tmp[i][yl - 1]; if (a[pos].r == old[i][yl - 1]) a[pos].r = tmp[i][yl - 1]; pos = tmp[i][yr]; if (a[pos].l == old[i][yr + 1]) a[pos].l = tmp[i][yr + 1]; if (a[pos].r == old[i][yr + 1]) a[pos].r = tmp[i][yr + 1]; } } int main() { read(n), read(m), read(q); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) b[i][j] = ++tot; for (int i = 1; i <= n; i++) { b[i][0] = ++tot; a[tot].r = b[i][1]; b[i][m + 1] = ++tot; a[tot].l = b[i][m]; } for (int i = 1; i <= m; i++) { b[0][i] = ++tot; a[tot].d = b[1][i]; b[n + 1][i] = ++tot; a[tot].u = b[n][i]; } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) a[b[i][j]] = (info) {b[i][j - 1], b[i][j + 1], b[i - 1][j], b[i + 1][j]}; while (q--) { char opt = getchar(); while (opt != 'H' && opt != 'V') opt = getchar(); int xl, yl, xr, yr; read(xl), read(yl), read(xr), read(yr); access(xl, yl, xr, yr); for (int i = xl; i <= xr; i++) { from[tmp[i][yl - 1]] = tmp[i][yl]; from[tmp[i][yr + 1]] = tmp[i][yr]; } for (int i = yl; i <= yr; i++) { from[tmp[xl - 1][i]] = tmp[xl][i]; from[tmp[xr + 1][i]] = tmp[xr][i]; } if (opt == 'H') { for (int i = yl, j = yr; i <= j; i++, j--) { swap(tmp[xl - 1][i], tmp[xl - 1][j]); swap(tmp[xr + 1][i], tmp[xr + 1][j]); } for (int i = xl; i <= xr; i++) swap(tmp[i][yl - 1], tmp[i][yr + 1]); } else { for (int i = xl, j = xr; i <= j; i++, j--) { swap(tmp[i][yl - 1], tmp[j][yl - 1]); swap(tmp[i][yr + 1], tmp[j][yr + 1]); } for (int i = yl; i <= yr; i++) swap(tmp[xl - 1][i], tmp[xr + 1][i]); } for (int i = xl; i <= xr; i++) { to[tmp[i][yl - 1]] = tmp[i][yl]; to[tmp[i][yr + 1]] = tmp[i][yr]; } for (int i = yl; i <= yr; i++) { to[tmp[xl - 1][i]] = tmp[xl][i]; to[tmp[xr + 1][i]] = tmp[xr][i]; } makeup(xl, yl, xr, yr); } for (int i = 1; i <= n; i++) getr(i, m); for (int i = 1; i <= n; i++) { ll ans = 0; for (int j = 1; j <= m; j++) ans += tmp[i][j]; printf("%lld ", ans); } printf("\n"); for (int j = 1; j <= m; j++) { ll ans = 0; for (int i = 1; i <= n; i++) ans += tmp[i][j]; printf("%lld ", ans); } printf("\n"); return 0; }