1. 程式人生 > >【省內訓練2018-10-26】矩陣

【省內訓練2018-10-26】矩陣

【思路要點】

  • 用十字連結串列維護整個矩陣,操作時將被操作的子矩形提取出來,改變周圍一圈點的連邊,再拼接回去即可,單次操作修改的邊數是 O ( N + M )
    O(N+M)
    的。
  • 具體而言,一種可行的實現方式是在矩形周圍增設一圈點作為哨兵節點,這些節點將不能被修改,用於提取子矩形。每個點記錄其左右兩個點的集合 { l , r
    } \{l,r\}
    和上下兩個點的集合 { u , d }
    \{u,d\}
    ,在翻轉時,一箇中間點的 r r l l 可能會互換,但集合 { l , r } \{l,r\} 是不變的。
  • 這樣的儲存方式在想要訪問 i . r i.r 的時候需要同時知道 i . l i.l i i i . r i.r 即為集合 { l , r } \{l,r\} 中不是 i . l i.l 的一個元素,這也是為什麼我們需要一圈哨兵節點來提取子矩形的原因。
  • 時間複雜度 O ( N M + 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;
}