题意:
给出一列数字,有m个问题,分别是数列前ai个数字中第i小的数字是多少。
思路:
正常的算法是每次都遍历一边找到第i小的数字,但是在数字范围大的时候会超时,所
不赞同用这样的方法。而名次树treap恰好能很方便的求出名次。treap是由平衡二叉
树和堆结合而成的。平衡树中一个节点的左儿子值都小于该节点,右儿子的值都大于该
节点。而堆得存在使得二叉树的深度能够保持的很好,所以在求出名次的时候直接算出
某一个节点的左右儿子的节点个数即可。
treap一般由结构体实现:其有v,s,r:分别代表着数值,左右儿子+自己的个数,优先级别。
函数组成有:插入、翻转、删除。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct Node {
Node *ch[2];
int r; //优先级
int v; //值
int s; //结点总数
Node(int v):v(v) {
ch[0] = ch[1] = NULL;
r = rand();
s = 1;
}
bool operator < (const Node& rhs) const {
return r < rhs.r;
}
int cmp(int x) const {
if(x==v) return -1;
return x < v ? 0:1;
}
void maintain() {
s = 1;
if(ch[0]!=NULL) s +=ch[0]->s;
if(ch[1]!=NULL) s +=ch[1]->s;
}
};
//旋转
void rotate(Node* &o,int d) {
Node* k = o->ch[d^1];
o->ch[d^1] = k->ch[d];
k->ch[d] = o;
o->maintain();
k->maintain();
o = k;
}
//插入
void insert(Node* &o,int x) {
if(o==NULL) o = new Node(x);
else {
int d = (x< o->v?0:1); //可能有相同的元素要插入
insert(o->ch[d],x);
if(o->ch[d]->r > o->r)
rotate(o,d^1);
}
o->maintain();
}
int get(Node* &o)
{
if(o == NULL) return 0;
return o->s;
}
int Find(Node* &o,int k)
{
int temp = get(o->ch[0]) + 1;
if(temp == k) return o->v;
if(temp > k) return Find(o->ch[0],k);
return Find(o->ch[1],k-temp);
}
const int maxn = 100005;
int n,m;
int a[maxn];
int main()
{
//freopen("in.txt","r",stdin);
Node* root = NULL;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n; i++) scanf("%d",&a[i]);
int j = 1;
for(int i = 1;i <= m; i++) {
int x;
scanf("%d",&x);
for(;j <= x; j++) {
insert(root,a[j]);
}
printf("%d\n",Find(root,i));
}
return 0;
}
- 自己写了一遍之后,多余的删除了。
#include <iostream>
#include <cstdio>
#include <math.h>
#include <algorithm>
using namespace std;
const int maxn = 100005;
struct Node
{
Node* ch[2];
int s,r,v;
Node (int v) : v(v) {
ch[0] = ch[1] = NULL;
r = rand();
s = 1;
}
void maintain() {
s = 1;
if(ch[0] != NULL) s += ch[0]->s;
if(ch[1] != NULL) s += ch[1]->s;
}
};
void rotate(Node* &o,int d)
{
Node *k = o->ch[d^1];
o->ch[d^1] = k->ch[d];
k->ch[d] = o;
k->maintain();
o->maintain();
o = k;
}
void insert(Node* &o,int x)
{
if(o == NULL) o = new Node(x);
else {
int d = x > o->v ? 1:0;
insert(o->ch[d],x);
if(o->ch[d]->r > o->r)
rotate(o,d^1);
}
o->maintain();
}
int get(Node* &o)
{
if(o == NULL) return 0;
else return o->s;
}
int Find(Node* &o,int k)
{
int temp = get(o->ch[0]) + 1;
if(temp == k) return o->v;
else if(temp > k) return Find(o->ch[0],k);
return Find(o->ch[1],k - temp);
}
int n,m;
int a[maxn];
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i = 1;i <= n; i++) {
scanf("%d",&a[i]);
}
int j = 1;
Node *root = NULL;
for(int i = 1;i <= m; i++) {
int x;
scanf("%d",&x);
for(;j <= x; j++) {
insert(root,a[j]);
}
printf("%d\n",Find(root,i));
}
return 0;
}
Treap树解决名次查询

本文介绍使用Treap树解决动态名次查询问题的方法。通过构造Treap树,可以高效地进行插入、删除和查询操作,实现快速查找指定名次的元素。Treap树结合了平衡二叉搜索树和堆的特点,保证了良好的树形结构。
2162

被折叠的 条评论
为什么被折叠?



