题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
输入输出格式
输入格式:
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
输出格式:
对于操作3,4,5,6每行输出一个数,表示对应答案
输入输出样例
输入样例#1:
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
输出样例#1:
106465
84185
492737
说明
时空限制:1000ms,128M
1.n的数据范围:n<=100000
2.每个数的数据范围:[-1e7,1e7]
Solution
这题是平衡树操作的果题,包含了平衡树的许多操作,作为平衡树模版题恰到好处。
本蒟蒻用了两种方法写此题,Treap写的很顺畅。Treap代码非常优美,简洁,常数小,下面是通过各个点的时间:
另外蒟蒻我还用Splay写了此题,代码长,没有Treap优美,跑得还慢太多(Splay常数硕大),我调试了一个晚上+第二天的一节晚修,才在一个神犇的帮助下,将这个写的很挫的Splay调试出来。测试的情况:
诚然,这比Treap慢太多了,然而Splay主要是维护序列区间操作的,我写来只是练一下手,见谅。
代码
Treap : 239ms
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define N 100005
using namespace std;
int n, cnt;
struct Treap{
Treap *L, *R;
int fix, val, size;
void Init(){L = R = NULL;}
inline int lsize(){return L ? L->size : 0;}
inline int rsize(){return R ? R->size : 0;}
}Node[N], *root;
Treap *NewTnode(){
Node[cnt].Init();
return Node+cnt++;
}
void Recount(Treap *&p){
p->size = p->lsize() + p->rsize() + 1;
}
void Treap_L_Rot(Treap *&a){
Treap *b = a->R;
a->R = b->L;
b->L = a;
a = b;
Recount(a->L);
Recount(a);
}
void Treap_R_Rot(Treap *&a){
Treap *b = a->L;
a->L = b->R;
b->R = a;
a = b;
Recount(a->R);
Recount(a);
}
void Treap_Insert(Treap *&p, int val){
if(!p){
p = NewTnode();
p->val = val;
p->size = 1;
p->fix = rand();
}
else if(val <= p->val){
p->size ++;
Treap_Insert(p->L, val);
if(p->L->fix < p->fix)
Treap_R_Rot(p);
}
else{
p->size ++;
Treap_Insert(p->R, val);
if(p->R->fix < p->fix)
Treap_L_Rot(p);
}
}
void Treap_Del(Treap *&p, int val){
if(val == p->val){
if(!p->L || !p->R){
if(p->L) p = p->L;
else p = p->R;
}
else if(p->L->fix < p->R->fix){
Treap_R_Rot(p);
p->size --;
Treap_Del(p->R, val);
}
else{
Treap_L_Rot(p);
p->size --;
Treap_Del(p->L, val);
}
}
else if(val < p->val){
p->size --;
Treap_Del(p->L, val);
}
else{
p->size --;
Treap_Del(p->R, val);
}
}
int Treap_Rank(Treap *p, int val){
if(!p) return 0;
if(val > p->val) return p->lsize() + Treap_Rank(p->R, val) + 1;
else return Treap_Rank(p->L, val);
}
int Treap_Find(Treap *p, int rank){
if(p->lsize()+1 == rank) return p->val;
if(p->lsize()+1 > rank) return Treap_Find(p->L, rank);
else return Treap_Find(p->R, rank-p->lsize()-1);
}
int Treap_pre(Treap *p, int val, int now){
if(!p) return now;
if(p->val < val) return Treap_pre(p->R, val, p->val);
return Treap_pre(p->L, val, now);
}
int Treap_suc(Treap *p, int val, int now){
if(!p) return now;
if(p->val > val) return Treap_suc(p->L, val, p->val);
return Treap_suc(p->R, val, now);
}
int main(){
scanf("%d", &n);
int opt, x;
for(int i = 1; i <= n; i++){
scanf("%d%d", &opt, &x);
if(opt == 1)
Treap_Insert(root, x);
else if(opt == 2)
Treap_Del(root, x);
else if(opt == 3)
printf("%d\n", Treap_Rank(root, x) + 1);
else if(opt == 4)
printf("%d\n", Treap_Find(root, x));
else if(opt == 5)
printf("%d\n", Treap_pre(root, x, root->val));
else printf("%d\n", Treap_suc(root, x, root->val));
}
return 0;
}
Splay : 1053ms
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define N 100010
using namespace std;
int n, m, cur;
int Read(){
int f = 1, x = 0; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return f * x;
}
void Print(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) Print(x / 10);
putchar(x % 10 + '0');
}
struct Tnode{
Tnode *son[2], *fa;
int val, size;
int Get_d(){return fa->son[1] == this;}
int Lsize(){return son[0] ? son[0]->size : 0;}
void Get_size(){size = Lsize() + (son[1] ? son[1]->size : 0) + 1;}
void Connect(Tnode *p, int d){(son[d] = p)->fa = this;}
}*Root, tree[N];
Tnode *NewTnode(){
return tree+cur++;
}
void Zig(Tnode *now, Tnode *&tag){
int d = now->Get_d();
Tnode *last = now->fa;
if(now->son[!d]) last->Connect(now->son[!d], d);
else last->son[d] = NULL;
last->Get_size();
if(last == tag){
now->fa = last->fa;
tag = now;
}
else last->fa->Connect(now, last->Get_d());
now->Connect(last, !d);
}
void Splay(Tnode *now, Tnode *&tag){
Tnode *last;
while(now != tag){
last = now->fa;
if(last != tag){(last->Get_d() ^ now->Get_d()) ? Zig(now, tag) : Zig(last, tag);}
Zig(now, tag);
}
now->Get_size();
}
void Insert(Tnode *p, int x){
p->size ++;
if(p->val >= x){
if(p->son[0]) Insert(p->son[0], x);
else{
Tnode *q = NewTnode(); q->val = x; q->Get_size();
p->Connect(q, 0);
Splay(q, Root);
}
}
else{
if(p->son[1]) Insert(p->son[1], x);
else{
Tnode *q = NewTnode(); q->val = x; q->Get_size();
p->Connect(q, 1);
Splay(q, Root);
}
}
}
void Delete(Tnode *&p, int x){
p->size --;
if(p->val == x){
if(!p->son[0] || !p->son[1]){
if(p->son[0]) p->son[0]->fa = p->fa, p = p->son[0];
else
{
if (p->son[1]) p->son[1]->fa = p->fa;
p = p->son[1];
}
}
else Delete(p->son[0], x);
}
else if(p->val > x) Delete(p->son[0], x);
else Delete(p->son[1], x);
}
Tnode *Get_pre(Tnode *now, int x, Tnode *op){
if(!now) return op;
if(now->val < x) return Get_pre(now->son[1], x, now);
return Get_pre(now->son[0], x, op);
}
Tnode *Get_suc(Tnode *now, int x, Tnode *op){
if(!now) return op;
if(now->val > x) return Get_suc(now->son[0], x, now);
return Get_suc(now->son[1], x, op);
}
int Get_Rank(Tnode *p, int x){
if(!p) return 0;
if(p->val < x) return p->Lsize() + 1 + Get_Rank(p->son[1], x);
return Get_Rank(p->son[0], x);
}
Tnode *Find(Tnode *p, int x){
if(p->Lsize()+1 == x) return p;
if(p->Lsize()+1 > x) return Find(p->son[0], x);
return Find(p->son[1], x-p->Lsize()-1);
}
int main(){
n = Read();
Root = NewTnode();
Root->val = -1e8;
Root->fa = NULL;
Root->son[1] = NewTnode();
Root->son[1]->val = 1e8;
Root->son[1]->fa = Root;
Root->son[1]->Get_size();
Root->Get_size();
int op, x;
Tnode *p;
for(int i = 1; i <= n; i++){
op = Read(); x = Read();
switch(op){
case 1 : {
Insert(Root, x); break;
}
case 2 : {
Splay(Get_pre(Root, x, Root), Root);
Splay(Get_suc(Root, x, Root), Root->son[1]);
Delete(Root, x);
break;
}
case 3 : {
x = Get_Rank(Root, x);
Print(x); putchar('\n');
break;
}
case 4 : {
p = Find(Root, x + 1);
Print(p->val); putchar('\n');
Splay(p, Root); break;
}
case 5 : {
p = Get_pre(Root, x, Root);
Print(p->val); putchar('\n');
Splay(p, Root); break;
}
default : {
p = Get_suc(Root, x, Root);
Print(p->val); putchar('\n');
Splay(p, Root); break;
}
}
}
return 0;
}
到这里,就到这里,我们一直都在路上。