洛谷P3369 普通平衡樹(Treap/Splay)
阿新 • • 發佈:2019-02-02
題目描述
您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作:
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;
}
到這裡,就到這裡,我們一直都在路上。