【省内训练2018-10-26】矩阵

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/83419817

【思路要点】

  • 用十字链表维护整个矩阵,操作时将被操作的子矩形提取出来,改变周围一圈点的连边,再拼接回去即可,单次操作修改的边数是 O(N+M)O(N+M) 的。
  • 具体而言,一种可行的实现方式是在矩形周围增设一圈点作为哨兵节点,这些节点将不能被修改,用于提取子矩形。每个点记录其左右两个点的集合 {l,r}\{l,r\} 和上下两个点的集合 {u,d}\{u,d\} ,在翻转时,一个中间点的 rrll 可能会互换,但集合 {l,r}\{l,r\} 是不变的。
  • 这样的存储方式在想要访问 i.ri.r 的时候需要同时知道 i.li.liii.ri.r 即为集合 {l,r}\{l,r\} 中不是 i.li.l 的一个元素,这也是为什么我们需要一圈哨兵节点来提取子矩形的原因。
  • 时间复杂度 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;
}
阅读更多
换一批

没有更多推荐了,返回首页