UVA11525题解

UVA11525

同步于本博客

如果你还不会康托展开,或者想要更好的用户体验,欢迎莅临本蒟蒻的博客,如果你还不会平板电视,也可以参考一下蒟蒻的博客

思路

首先不难看出,这是一道逆康托展开的题目。但是 \(n\) 的计算方式貌似有点奇怪,有没有感觉有一点熟悉?往上翻翻。

这和康托展开公式很相似嘛,考虑从这里入手。

手模样例不难看出,\(S_i\) 的意义就是:对于第 \(i\) 个数字,后面的数字中有多少个比当前位大。因此,我们就可以直接考虑维护每个数字找第 \(k\) 大这个过程。

方法有很多,题解中也有不少。

可以考虑时间复杂度为 \(O(n\log n)\) 的但常数比较大的权值线段树或平衡树,也可以考虑时间复杂度为 \(O(n\log^2n)\) 但是常数较小的二分 + 树状数组,个人认为最优秀的是时间复杂度为 \(O(n\log n)\) 并且常数很小的树状数组 + 倍增。

但是由于倍增解法各位大佬已经讲得很清楚了(本蒟蒻懒),因此蒟蒻这里带来码量极小(头文件和红黑树命名除外)的平板电视中的红黑树实现。

代码实现

#include<iostream>
#include<ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>rbt;
int k,T;
int main()
{
	cin>>T;
	while(T--)
	{
		cin>>k;
		for(int i=1;i<=k;i++)rbt.insert(i);
		for(int i=1,a;i<=k;i++)
		{
			cin>>a;
			auto it=rbt.find_by_order(a);//返回排名为a的元素
			cout<<*it<<(i!=k?' ':'\n');
			rbt.erase(it);
		}
	}
	return 0;
}

个人认为学会平板电视,对于一些需要用到简单平衡树的题目来说还是很方便的。但是对于正经的数据结构题,还是老老实实的手写平衡树吧,小心被卡常

最后,本题解难免有一些讲解的不好的地方,欢迎各位大佬神犇指导。

posted @ 2023-07-23 22:26  week_end  阅读(8)  评论(0编辑  收藏  举报