1. 程式人生 > >洛谷P3369 普通平衡樹(Treap/Splay)

洛谷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;
}

到這裡,就到這裡,我們一直都在路上。