洛谷P3369 普通平衡树(Treap/Splay)

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
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;
}

到这里,就到这里,我们一直都在路上。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值