【题解】小澳的方阵
题目
题目来源: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;
}
后记
顺带一提,类似的题目还有很多,只不过方法有所不同。
有一些利用了差分,加上线段树优化以后才能通过。而另一些甚至于要用二维线段树才能解决。
所以,这种东西很难类比,因为接近的题目也不一定是相同的做法。
本文来自博客园,作者 5ab,转载请注明链接哦 qwq
博客迁移啦,来看看新博客吧 -> https://5ab-juruo.oier.space/