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;
}
个人认为学会平板电视,对于一些需要用到简单平衡树的题目来说还是很方便的。但是对于正经的数据结构题,还是老老实实的手写平衡树吧,小心被卡常。
最后,本题解难免有一些讲解的不好的地方,欢迎各位大佬神犇指导。