牛客训练赛

题意

一个 n ∗ n n*n nn 的初始全零的矩阵,按如下方法填数

1 2 3
6 5 3
7 8 9

但是这样子太过简单,所以每一次操作会选择一个子矩阵,请你在其子矩阵上进行填数,并在最后输出整个矩阵

思路
显然满足和染色一个道理, 我们只需要从后向前染色即可, 总之暴力可过, 不过需要优化, eg如果染色当前(x, y)点, 发现(x, y)点已经被修改了,我们可以通过被修改的数据直接跳到下一个点即可,还有可以通过线段树来解, 建n棵线段树, 每一棵表示一行中的染色情况, 对于如果已经染色的点, 就不再染色, 此处的建树, 和查询都做了相应的优化, 代码细节处理。

#include <bits/stdc++.h>

using namespace std;
const int N = 2e3 + 5, M = 3e3 + 5;
int n, m, x[M], y[M], k[M];
int a[N], w[N][N<<2]; // w[N][N<<2], N棵线段树

void update(int p, int l, int r, int x, int y, int v, int id)
{
	if(w[id][p] != 0) return;
	if(x <= l && r <= y)
	{
		if(!w[id][p]) w[id][p] = v;
		return;
	}
	int mid = l + r >> 1;
	if(mid >= x) update(p << 1, l, mid, x, y, v, id);
	if(mid < y) update(p<<1|1, mid + 1, r, x, y, v, id);
}

void pushdown(int l, int r, int p, int id)// 将最大值更新到叶子节点
{
	w[id][p] = max(w[id][p], w[id][p >> 1]);
	if(l == r) return;
	int mid = l + r >> 1;
	pushdown(l, mid, p<<1, id);
	pushdown(mid + 1, r, p<<1|1, id);
}

void init(int l, int r, int p)
{
	if(l == r)
	{
		a[l] = p;
		return;
	}
	int mid = l + r >> 1;
	init(l, mid, p << 1);
	init(mid + 1, r, p<<1|1);
}
int main()
{
	cin >> n >> m;
	init(1, n, 1);
	for(int i = 1; i <= m; i++) cin >> x[i] >> y[i] >> k[i];
	for(int i = m; i >= 1; i --)
	{
		for(int j = 0; j < k[i]; j ++)
		{
			update(1, 1, n, y[i], y[i] + k[i] - 1, i, x[i] + j);
		}
	}
	for(int i = 1; i <= n; i++) pushdown(1, n, 1, i);
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= n; j++)
		{
			int t = w[i][a[j]];
			if(t == 0) cout << 0 << " \n"[j == n];
			else
			{
				int r = i - x[t] + 1, c = j - y[t] + 1;
				cout << (r&1?(r-1)*k[t] + c:(r - 1)*k[t] + k[t] - c + 1) << " \n"[j==n];
			}

		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值