Knight Tournament_CodeForces 357C

题目

Hooray! Berl II, the king of Berland is making a knight tournament. The king has already sent the message to all knights in the kingdom and they in turn agreed to participate in this grand event.

As for you, you're just a simple peasant. There's no surprise that you slept in this morning and were late for the tournament (it was a weekend, after all). Now you are really curious about the results of the tournament. This time the tournament in Berland went as follows:

  • There are n knights participating in the tournament. Each knight was assigned his unique number — an integer from 1 to n.
  • The tournament consisted of m fights, in the i-th fight the knights that were still in the game with numbers at least li and at most ri have fought for the right to continue taking part in the tournament.
  • After the i-th fight among all participants of the fight only one knight won — the knight number xi, he continued participating in the tournament. Other knights left the tournament.
  • The winner of the last (the m-th) fight (the knight number xm) became the winner of the tournament.

You fished out all the information about the fights from your friends. Now for each knight you want to know the name of the knight he was conquered by. We think that the knight number b was conquered by the knight number a, if there was a fight with both of these knights present and the winner was the knight number a.

Write the code that calculates for each knight, the name of the knight that beat him.

Input

The first line contains two integers nm (2 ≤ n ≤ 3·105; 1 ≤ m ≤ 3·105) — the number of knights and the number of fights. Each of the following m lines contains three integers li, ri, xi (1 ≤ li < ri ≤ nli ≤ xi ≤ ri) — the description of the i-th fight.

It is guaranteed that the input is correct and matches the problem statement. It is guaranteed that at least two knights took part in each battle.

Output

Print n integers. If the i-th knight lost, then the i-th number should equal the number of the knight that beat the knight number i. If the i-th knight is the winner, then the i-th number must equal 0.

Examples

Input

4 3
1 2 1
1 3 3
1 4 4

Output

3 1 4 0 

Input

8 4
3 5 4
3 7 6
2 8 8
1 8 1

Output

0 8 4 6 4 8 6 1 

Note

Consider the first test case. Knights 1 and 2 fought the first fight and knight 1 won. Knights 1 and 3 fought the second fight and knight 3 won. The last fight was between knights 3 and 4, knight 4 won.

题目大意

 输入n表示骑士数,然后输入m表示战斗数

接下来是m行战斗

每行包括li ri xi 表示从[li,ri]这个区间的所有骑士都被xi打败

最后要求输出每个骑士是被谁直接打败的,最终获胜的骑士输出0

算法:并查集

 https://blog.csdn.net/baidu_41907100/article/details/84956027

 

int pre[1000 ];
int find(int x)              				//找祖先并压缩路径 
{
    return pri[x]==x?x:pri[x]=find(pri[x]);
}
 
 
 
void join(int x,int y)                                                                                                    //判断x y是否连通,                                                                                            //如果已经连通,就不用管了 //如果不连通,就把它们所在的连通分支合并起,
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
        pre[fx ]=fy;
}
 

 代码

 

#include<iostream>
#define maxn 300100
using namespace std;
int pri[maxn],ans[maxn];
int find(int x)              				//找祖先并压缩路径 
{
    return pri[x]==x?x:pri[x]=find(pri[x]);
}
void join(int l,int r,int x)				   //join函数视情况修改 
{
	while(l<=r)
	{
		int f=find(l);
		if(f==l)              			//祖先是自己,那就说明了,这个点是第一次被打败,那么他的祖先赋值为胜者 
		{
			pri[l]=l+1;  				//然后让他的祖先成为右边的数 
			ans[l]=x;
		}
		l=pri[l];						//循环运行的改变条件
										//让l成为他的祖先,如果l进行了上述if操作,那么也就是区间右移一位
										//如果没有执行上述if操作(也就是说 区间早就被压缩过),那么直接跳到他的祖先
										//至于他的祖先也就是更新过区间的右端,因为我们压缩的时候就是将其祖先设为他的右端 
	}
}
int main()
{
	int n,m; 
	cin>>n>>m;;
	for(int i=1;i<=n+1;i++)
		pri[i]=i; 						//初始化祖先为自己 
	while(m--)
	{
		int li,ri,xi;
		cin>>li>>ri>>xi;
		join(li,xi-1,xi);join(xi+1,ri,xi);		//将区间join x不变 
	}
	for(int i=1;i<=n;i++)
		cout<<ans[i]<<" ";
	cout<<endl;
	return 0;
}

 分析

一开始想到的是直接模拟,但是发现test到13就出现了超时问题

然后这里需要优化,因为可能大部分的询问都是重复无意义的的,那么就需要我们通过某些操作跳过已经访问过的点

比如 某次战斗区间为[l,r],假如又有一次战斗[l',r'],其中l<l'<r,r'>r,因为[l',r]均已访问,那么我们可以直接让l'跳到r+1,即原区间[l,r]被缩成一点, 至于这一步跳过操作可以通过并查集来完成

 

看我们的代码

首先看主函数,首先将自己的祖先定义为自己

然后注意到,在每次输入战斗的时候,要join两次,join(li,xi-1,xi);join(xi+1,ri,xi),这样做是为了防止更改获胜者的祖先

 

继续看我们的函数

find函数就是并查集的寻找并压缩路径的函数

join函数稍加改动

void join(int l,int r,int x)				   //join函数视情况修改 
{
	while(l<=r)
	{
		int f=find(l);
		if(f==l)              			//祖先是自己,那就说明了,这个点是第一次被打败,那么他的祖先赋值为胜者 
		{
			pri[l]=l+1;  				//然后让他的祖先成为右边的数 
			ans[l]=x;
		}
		l=pri[l];						//循环运行的改变条件
										//让l成为他的祖先,如果l进行了上述if操作,那么也就是区间右移一位
										//如果没有执行上述if操作(也就是说 区间早就被压缩过),那么直接跳到他的祖先
										//至于他的祖先也就是更新过区间的右端,因为我们压缩的时候就是将其祖先设为他的右端 
	}
}

 这里要明白我们是如何通过并查集跳过一段已经更新过的区间的:

首先要判断一下起点是否是第一次被打败,如果是第一次被打败,那么就说明他从未被更新过;如果他的祖先不是他自己,那就说明之前的战斗中已经将这个点更新过了。

如果这个点是第一次被打败(首次更新),那么让他的祖先赋值为他右边的一个点,但是ans[l]是这次战斗的胜者

不管他是不是第一次被更新,都让这个点变成他的祖先

{

   假如他已经被更新过了,那么他的祖先就会是之前更新区间的右端点(因为我们每次更新都是赋值未被更新点的祖先为其右边第一个点)

   假如他没有被更新过,那么就相当于进行l++操作,点右移

}

通过这些完成了区间的合并!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cherish_lii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值