【题解】小澳的方阵

题目

题目来源:20200523 模拟赛 T1;(具体版权未知)。

测试链接:咕咕咕

题目背景

小澳最近迷上了考古,他发现秦始皇的兵马俑布局十分有特点,热爱钻研的小澳打算在电脑上还原这个伟大的布局。

题目描述

他努力钻研,发现秦始皇布置兵马俑是有一定规律的。兵马俑阵总共有 \(n\)\(m\) 列,秦始皇在布置的时候每次会指定一行或一列,然后指定一个兵种,使得这一行或者这一列上全部放上这一个兵种。如果这一行上以前放过其它的兵种,那么他会拔掉以前的兵种改成现在他命令的兵种。

小澳从秦朝的文献中找到了布置这个方阵的操作顺序,他希望你能告诉他布局完成后整个兵马俑阵是什么样子的。

输入格式

输入文件共 \(q+1\) 行。

输入文件第 \(1\) 行包括三个正整数 \(n\)\(m\)\(q\),分别表示兵马俑阵的行数和列数,以及秦始皇总的操作数。

接下来 \(q\) 行,每行三个正整数 \(x\)\(y\)\(z\)\(x\) 表示操作种类:

  • \(x=1\),表示给第 \(y\) 行(\(y\le n\))全部放上 \(z\) 这个兵种;
  • \(x=2\),则表示给第 \(y\) 列(\(y\le m\))全部放上 \(z\) 这个兵种。

输出格式

输出文件共 \(n\) 行,每行 \(m\) 个整数,分别用空格隔开。表示最后方阵上每个位置放的兵种,如果某个位置没有被操作过输出 \(0\)

评测限制

从 matrix.in 中读入,输出到 matrix.out。

评测时间限制 \(1000\ \textrm{ms}\),空间限制 \(256\ \textrm{MiB}\)

数据范围与约定

  • 对于 \(20\%\) 的数据,\(nm\le 25\)
  • 对于 \(30\%\) 的数据,\(q\le 2000\)
  • 对于 \(100\%\) 的数据,\(n,m\le 1000\)\(nm\le 10^5\)\(q\le 10^6\)

分析

题意是,对于一个矩阵,每一次给一行或一列赋值,后赋值的会覆盖前面赋值的。输出这个矩阵赋值后的结果。

\(30\ \texttt{pts}\)

这就是一个简单的大暴力,每一次都赋值一遍即可。

\(100\ \texttt{pts}\)

想到这一点,我们不妨看一看数据范围:\(\large{q\le 10^6}\)。也就是说,会多次修改同一行或同一列。

那么,我们每一次都赋值就非常慢,而且后面会被覆盖。那怎么办呢?

我们不妨倒过来想:影响一个格子的兵种的因素是什么?显然是横竖分别赋值的兵种中较晚的一个。

所以,有一个思路就非常自然:记录每一行和每一列最后修改的内容和时间。输出每一个格子的时候,检查横竖的最晚时间并输出对应兵种。

事实上,这个做法就是正解。我们只需要在修改的时候打上「Lazy Tag」即可。复杂度 \(\Theta(nm+q)\) 绰绰有余。

Code

这实际上就是一个不折不扣的模拟,所以代码量非常少。

#include <cstdio>
#include <cctype>
using namespace std;

const int max_n = 1000;
struct lin
{
	int tim, val;
};

lin row[max_n] = {}, col[max_n] = {};

inline int read()
{
	int ch = getchar(), t = 1, n = 0;
	while (isspace(ch)) { ch = getchar(); }
	if (ch == '-') { t = -1, ch = getchar(); }
	while (isdigit(ch)) { n = n * 10 + ch - '0', ch = getchar(); }
	return n * t;
}

int main()
{
	int n = read(), m = read(), q = read(), opt, id, tid;
	
	for (int i = 0; i < q; i++)
	{
		opt = read(), id = read() - 1, tid = read();

		if (opt & 1)
			row[id].tim = i + 1, row[id].val = tid;
		else
			col[id].tim = i + 1, col[id].val = tid;
	}

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			if (row[i].tim > col[j].tim)
				printf("%d ", row[i].val);
			else
				printf("%d ", col[j].val);
		}

		putchar('\n');
	}

	return 0;
}

后记

顺带一提,类似的题目还有很多,只不过方法有所不同。

有一些利用了差分,加上线段树优化以后才能通过。而另一些甚至于要用二维线段树才能解决。

所以,这种东西很难类比,因为接近的题目也不一定是相同的做法。

posted @ 2020-06-20 13:58  5ab  阅读(128)  评论(0编辑  收藏  举报