Knight Tournament_CodeForces 357C

本文解析了一个基于骑士对决的算法问题,使用并查集优化解决骑士间战斗结果的查询,避免重复计算,提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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.youkuaiyun.com/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++操作,点右移

}

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

内容概要:本文档详细介绍了一个基于MATLAB实现的跨尺度注意力机制(CSA)结合Transformer编码器的多变量时间序列预测项目。项目旨在精准捕捉多尺度时间序列特征,提升多变量时间序列的预测性能,降低模型计算复杂度与训练时间,增强模型的解释性和可视化能力。通过跨尺度注意力机制,模型可以同时捕获局部细节和全局趋势,显著提升预测精度和泛化能力。文档还探讨了项目面临的挑战,如多尺度特征融合、多变量复杂依赖关系、计算资源瓶颈等问题,并提出了相应的解决方案。此外,项目模型架构包括跨尺度注意力机制模块、Transformer编码器层和输出预测层,文档最后提供了部分MATLAB代码示例。 适合人群:具备一定编程基础,尤其是熟悉MATLAB和深度学习的科研人员、工程师和研究生。 使用场景及目标:①需要处理多变量、多尺度时间序列数据的研究和应用场景,如金融市场分析、气象预测、工业设备监控、交通流量预测等;②希望深入了解跨尺度注意力机制和Transformer编码器在时间序列预测中的应用;③希望通过MATLAB实现高效的多变量时间序列预测模型,提升预测精度和模型解释性。 其他说明:此项目不仅提供了一种新的技术路径来处理复杂的时间序列数据,还推动了多领域多变量时间序列应用的创新。文档中的代码示例和详细的模型描述有助于读者快速理解和复现该项目,促进学术和技术交流。建议读者在实践中结合自己的数据集进行调试和优化,以达到最佳的预测效果。
<think>嗯,用户遇到了“函数或变量 'tournament_selection' 无法识别”的问题。这个问题通常是因为MATLAB环境中没有定义这个函数。首先,我需要确认用户是否已经正确安装了遗传算法工具箱或者相关的第三方工具箱,比如Global Optimization Toolbox。如果已经安装,可能需要检查拼写是否正确,比如有没有大小写错误或者拼写错误。 如果确认没有安装相应的工具箱,可能需要自己实现锦标赛选择算法。这时候应该考虑用户是否有足够的编程能力来编写这个函数。锦标赛选择的基本逻辑是从种群中随机选择若干个个体,然后从中选出适应度最高的作为胜出者。用户可能需要一个简单的示例代码来参考。 另外,用户可能在调用某个函数或脚本时,路径设置不正确,导致MATLAB找不到自定义的'tournament_selection.m'文件。这时候需要检查文件是否在当前工作目录或添加到MATLAB的搜索路径中。 还需要考虑用户是否混淆了不同的遗传算法框架,比如使用的是自己编写的代码还是第三方库。如果是第三方库,可能需要查阅对应的文档,看看函数名称是否正确,或者是否需要额外的配置步骤。 总结下来,可能的解决步骤包括:检查拼写和大小写,验证工具箱安装情况,确保自定义函数在正确路径,提供示例实现代码,或者建议使用内置函数代替。需要一步步引导用户排查问题,并提供具体的解决方案,比如示例代码,帮助他们实现或找到正确的函数。</think>在 MATLAB 中出现「函数或变量 'tournament_selection' 无法识别」错误通常有以下几种原因及解决方案: --- ### **1. 未安装遗传算法工具箱** - **问题本质**:`tournament_selection` 是遗传算法中常用的选择算子,但 MATLAB 官方并未直接提供此命名函数 - **解决方法**: - 使用 Global Optimization Toolbox 的 `select` 函数(需先安装该工具箱): ```matlab % 通过设置 options 调用锦标赛选择 options = optimoptions('ga', 'SelectionFcn', @selectiontournament); ``` - 验证工具箱安装:命令行输入 `ver` 查看已安装工具箱列表 --- ### **2. 自定义函数未正确实现** - **问题本质**:用户可能参考了第三方代码但未自行实现锦标赛选择函数 - **解决方法**:添加自定义函数 `tournament_selection.m` 到当前路径: ```matlab function selected = tournament_selection(population, fitness, tournament_size) [pop_size, ~] = size(population); selected = zeros(pop_size, 1); for i = 1:pop_size % 随机选择 tournament_size 个参赛者 candidates = randperm(pop_size, tournament_size); [~, best_idx] = max(fitness(candidates)); selected(i) = candidates(best_idx); end end ``` --- ### **3. 文件路径问题** - **验证步骤**: 1. 确认 `.m` 文件存在于当前工作目录 2. 检查文件名拼写是否完全一致(区分大小写) 3. 在命令行输入 `which tournament_selection` 查看路径解析 --- ### **4. 第三方工具箱调用问题** - **特殊场景**:若使用第三方遗传算法框架(如 _MATLAB Central_ 的代码库) - 检查文档确认函数命名是否为 `tournament_selection` - 确保所有依赖文件已正确加载 --- ### **推荐调试流程** 1. 在命令行尝试直接调用函数,确认基础可用性 2. 使用 `addpath` 添加自定义函数所在文件夹 3. 检查函数参数是否匹配调用时的输入格式 **示例正确调用**: ```matlab % 假设 population 是 N×D 矩阵,fitness 是 N×1 向量 selected_parents = tournament_selection(population, fitness, 3); % 锦标赛规模=3 ``` --- 如果问题仍未解决,建议提供具体调用代码片段,以便进一步分析错误上下文。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Cherish_lii

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

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

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

打赏作者

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

抵扣说明:

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

余额充值