CF356A Knight Tournament

题目大意

nn 个骑士,他们每个人都被从 1n1-n 进行编号。

他们现在需要进行一次比赛,且总共会进行 mm 场比赛。

每场比赛会在编号在 LiRiL_i-R_i 这段区间内的骑士之间举行,对于每场比赛,它的胜利者的编号为 XiX_i,其他的骑士会出局,之后无法进行比赛。最后留下的骑士就是这次比赛的最终胜利者。

比赛结束后,每个骑士都想知道他被哪一个骑士击败了,请你告诉他们。

解题思路

首先可以想到,LiRiL_i - R_i 所有人被 XiX_i 击败。

那么可以用线段树将这一段标记为 XiX_i

但是会有一个问题,如果一个数 opop,被多个区间包含,那么只能算被第一个区间击败。

所以将事件倒序处理即可。

时间复杂度 O(mlogn)\mathcal O(m \log n)

CODE

#include <bits/stdc++.h>

using namespace std;

const int _ = 5e5 + 7;

int n, m;

int l[_], r[_], x[_];

int tr[_ << 2];

void push_down(int o)
{
	if(tr[o])
	{
		tr[o << 1] = tr[o];
		tr[o << 1 | 1] = tr[o];
		tr[o] = 0;
	}
}

void update(int o, int l, int r, int L, int R, int val)
{
	if(r < L || l > R) return;
	if(L <= l && r <= R)
	{
		tr[o] = val;
		return;
	}
	push_down(o);
	int mid = (l + r) >> 1;
	update(o << 1, l, mid, L, R, val);
	update(o << 1 | 1, mid + 1, r, L, R, val);
}

void print(int o, int l, int r)
{
	if(l == r)
	{
		cout << tr[o] << " ";
		return;
	}
	push_down(o);
	int mid = (l + r) >> 1;
	print(o << 1, l, mid);
	print(o << 1 | 1, mid + 1, r);
}

signed main()
{
	cin >> n >> m;
	for(int i = 1; i <= m; ++i) cin >> l[i] >> r[i] >> x[i];
	for(int i = m; i >= 1; --i)
	{
		if(x[i] == l[i])
		{
			update(1, 1, n, l[i] + 1, r[i], x[i]);
		}
		else if(x[i] == r[i])
		{
			update(1, 1, n, l[i], r[i] - 1, x[i]);
		}
		else
		{
			update(1, 1, n, l[i], x[i] - 1, x[i]);
			update(1, 1, n, x[i] + 1, r[i], x[i]);
		}
	}
	print(1, 1, n);
	return 0;
}
posted @ 2021-11-14 21:43  蒟蒻orz  阅读(7)  评论(0)    收藏  举报  来源