模板题:treap模板可直接用 改变一下主函数输入就可以 具体看代码注释
#include<bits/stdc++.h>
using namespace std;
const int N = 5000001;
int id[N];
struct Node {
int size;//以当前节点为根的子树的大小
int rank;//用以维护treap的随机数
int key;//键值 这里是武功级别
Node* son[2];
// 小于比较 自身rank和传入的rank
bool operator < (const Node& a) const {
return rank < a.rank;
}
// 比较x和自身key
// 相等返回-1
// x<key 左子树 0
// x>key 右子树 1
int cmp(int x) const {
if (key == x) return -1;
return x < key ? 0 : 1;
}
// 更新子树的大小 旋转时treap存在节点需要更新子树大小
void update() {
size = 1;
if (son[0]) size += son[0]->size;
if (son[1]) size += son[1]->size;
}
};
// 旋转 d=0左旋 d=1右旋
void rotate(Node*& o, int d) {
Node* k = o->son[1 ^ d];
o->son[1 ^ d] = k->son[d];
k->son[d] = o;
o->update();
k->update();
o = k;//这里把原来指向o的位置改了 所以原来指向o的指针现在相当于指向k 也是传指针的引用的原因
}
void insert(Node*& o, int x) {
if (!o) {
o = new Node();//直接在原位置创建指针 这是穿指针的引用的原因
o->son[0] = o->son[1] = nullptr;
o->rank = rand();
o->key = x;
o->size = 1;
}
else {
int d = o->cmp(x);
insert(o->son[d], x);
o->update();
if (o < o->son[d]) {
rotate(o, 1 ^ d);
}
}
}
// 返回第k大的数
int kth(Node* o, int k) {
if (o == nullptr || k<0 || k>o->size) {
return -1;
}
else {
int s = (o->son[1] == nullptr) ? 0 : o->son[1]->size;
if (k == s + 1) return o->key;
else if (k < s + 1) {
return kth(o->son[1], k);
}
else {
return kth(o->son[0], k - s - 1);
}
}
}
// 找到k的位次
int find(Node* o, int k) {
if (!o) return -1;
else {
int d = o->cmp(k);
if (d == -1) {
return o->son[1] == nullptr ? 1 : o->son[1]->size + 1;
}
else if (d == 1) {
return find(o->son[1], k);
}
else {
int tmp = find(o->son[0], k);
if (tmp == -1) return -1;
return o->son[1] == nullptr ? tmp + 1 : tmp + o->son[1]->size + 1;
}
}
}
void deleteNode(Node* root) {
if (!root) return;
deleteNode(root->son[0]);
deleteNode(root->son[1]);
delete root;
}
/*
本题的大概意思是 给定序列
指明某一时刻 序列第几大的元素
和排序有关选用treap实现名次树
关键在于读取的方式
*/
int n, m;
int val[1000010];
int main()
{
while (cin >> n >> m) {
Node* root = NULL;
int id = 1;//代表当前想要查询第几大
//这是一个很好的思想由于本题需要延迟插树 先缓存到数组中
for (int i = 1; i <= n; i++)
cin >> val[i];
//关键在于如何获得对应时刻的搜索树
int pre = 1;
for (int i = 1; i <= m; i++) {
int t;
cin >> t;
//表示继续接着插入 从上一次的id到本次需要读取的位置 表示t时刻
for (int j = pre; j <= t; j++) {
insert(root, val[j]);
}
cout<<kth(root, root->size-id+1)<<endl;
id++;
pre = t+1;//保存上一时刻插入的位置
}
deleteNode(root);
}
return 0;
}