普通平衡树[splay]

参考:

http://blog.csdn.net/clove_unique/article/details/50630280

gty课件

找一个好的风格太难了,自己习惯用struct,就强行用struct写了一下数组版的,同时加了些宏简化代码

都是迭代写法

splay要维护fa指向父亲

rotate是把x转到fa,要更新f和x

splay是把x转到tar的孩子,x成为root就是tar=0,注意更新root

ins考虑空树,考虑已经存在,插入新节点的话要保留last到最后处理父亲,更新父亲(其实就是更新了这棵树,由于splay没必要更新祖先)然后做splay

(递归写法的传引用已经解决了设置祖先的问题)

del

先找要删除的,splay到根

1.多个直接--

2.空树直接root=0

3.只有一个儿子,令独生子变成根,删去该点。
4.左右儿子都有。找到左子树中权值最大的点,将其 splay 到左儿子的位置。然后将 整棵右子树挂在左儿子的右边。删除节点。

其他操作差不多了

ps:比treap慢了一倍

//
//  main.cpp
//  splay
//
//  Created by Candy on 27/11/2016.
//  Copyright © 2016 Candy. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=2e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}
struct node{
    int fa,ch[2],v,w,size;
}t[N];
int cnt,root;
inline int wh(int x){return t[pa].ch[1]==x;}
inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
inline void rotate(int x){//x-->pa
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(g) t[g].ch[wh(f)]=x;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    t[x].fa=g;
    update(f);update(x);
}
inline void splay(int x,int tar){//x-->x.fa==tar
    for(;t[x].fa!=tar;rotate(x))
        if(t[pa].fa!=tar) rotate(wh(x)==wh(pa)?pa:x);
    if(tar==0) root=x;
}

inline int nw(int v){
    cnt++;
    t[cnt].v=v;t[cnt].ch[0]=t[cnt].ch[1]=t[cnt].fa=0;
    t[cnt].w=t[cnt].size=1;
    return cnt;
}
inline void ins(int v){
    if(root==0){root=nw(v);return;}//empty tree
    int x=root,last=0;
    while(x!=0){
        if(t[x].v==v){t[x].w++;t[x].size++;splay(x,0);return;}
        last=x;
        if(v<t[x].v) x=lc; else x=rc;
    }
    int tmp=nw(v);
    if(v<t[last].v) t[last].ch[0]=tmp;
    else t[last].ch[1]=tmp;
    t[tmp].fa=last;update(last);//no need for ancient because splay()
    splay(tmp,0);
}
inline int find(int v){
    int x=root;
    while(x!=0){
        if(v==t[x].v) break;
        if(v<t[x].v) x=lc;
        else x=rc;
    }
    if(x!=0) splay(x,0);
    return x;
}
inline int pre(){
    int x=t[root].ch[0];
    while(rc) x=rc;
    return x;
}
inline void del(int v){
    int x=find(v);
    if(t[x].w>1) {t[x].w--,t[x].size--;return;}
    if(lc==0&&rc==0) root=0;
    else if(rc==0) t[lc].fa=0,root=lc;
    else if(lc==0) t[rc].fa=0,root=rc;
    else{
        int tmp=t[root].ch[0];
        while(t[tmp].ch[1]) tmp=t[tmp].ch[1];
        splay(tmp,x);
        t[tmp].ch[1]=rc;t[rc].fa=tmp;
        t[tmp].fa=0;
        root=tmp;
        update(root);
    }
}
inline int rnk(int v){
    int x=root,ls=0;
    while(x!=0){
        if(t[x].v==v){
            int ans=ls+t[lc].size+1;
            splay(x,0);
            return ans;
        }
        if(v<t[x].v) x=lc;
        else ls+=t[lc].size+t[x].w,x=rc;
    }
    return -1;
}
inline int kth(int k){
    int x=root,ls=0;
    while(x!=0){
        int tmp=ls+t[lc].size;
        if(tmp+1<=k&&k<=tmp+t[x].w){
            splay(x,0);return t[x].v;
        }
        if(k<=tmp) x=lc;
        else ls=tmp+t[x].w,x=rc;
    }
    return -1;
}
inline int pre(int v){
    int ans=0,x=root;
    while(x!=0){
        if(t[x].v<v) ans=x,x=rc;
        else x=lc;
    }
    return ans;
}
inline int suf(int v){
    int ans=0,x=root;
    while(x!=0){//printf("suf %d %d\n",x,t[x].v);
        if(v<t[x].v) ans=x,x=lc;
        else x=rc;
    }
    return ans;
}
int n,op,x,ans;
int main(int argc, const char * argv[]){
    n=read();
    while(n--){
        op=read();x=read();
        switch(op){
            case 1:ins(x);break;
            case 2:del(x);break;
            case 3:printf("%d\n",rnk(x));break;
            case 4:printf("%d\n",kth(x));break;
            case 5:ans=pre(x);printf("%d\n",t[ans].v);break;
            case 6:ans=suf(x);printf("%d\n",t[ans].v);break;
        }
    }
    return 0;
}
时间: 2024-11-05 22:57:38

普通平衡树[splay]的相关文章

【BZOJ3224】Tyvj 1728 普通平衡树 Splay

Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大的数)6. 求x的后继(后继定义为大于x,且最小的数) Input 第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6) Output 对于操作3,4,5,6每行输

bzoj3224 普通平衡树(splay 模板)

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 11427  Solved: 4878[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为

bzoj 1588 平衡树 splay

1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 15446  Solved: 6076[Submit][Status][Discuss] Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其

Tyvj P1729 文艺平衡树 Splay

题目: http://tyvj.cn/p/1729 P1729 文艺平衡树 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 此为平衡树系列第二道:文艺平衡树 描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数

BZOJ3223: Tyvj 1729 文艺平衡树 [splay]

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3595  Solved: 2029[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次

【BZOJ1125】【POI2008】Poc 原名:Train hash+离散化+平衡树(splay)

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45739895"); } 题解: 首先我们发现对于每个串,我们把它hash一下,然后建一棵平衡树来支持"插入"."删除"."下传标记"这三种操作就可以记录并更新一个点的答案了

[BZOJ3223] [Tyvj1729] 文艺平衡树 (splay)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数 接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n Output 输出一行n个数字,表示原始序列经过m次变换后的结果 Sample Input 5 3 1 3

【转】 史上最详尽的平衡树(splay)讲解与模板(非指针版spaly)

ORZ原创Clove学姐: 变量声明:f[i]表示i的父结点,ch[i][0]表示i的左儿子,ch[i][1]表示i的右儿子,key[i]表示i的关键字(即结点i代表的那个数字),cnt[i]表示i结点的关键字出现的次数(相当于权值),size[i]表示包括i的这个子树的大小:sz为整棵树的大小,root为整棵树的根. 再介绍几个基本操作: [clear操作]:将当前点的各项值都清0(用于删除之后) inline void clear(int x){ ch[x][0]=ch[x][1]=f[x]

JZYZOJ1998 [bzoj3223] 文艺平衡树 splay 平衡树

http://172.20.6.3/Problem_Show.asp?id=1998 平衡树区间翻转的板子,重新写一遍,给自己码一个板子. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstdlib> 7 using namespace std; 8 cons

1500. [NOI2005]维修数列【平衡树-splay】

Description 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格 Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行一条命令,格式参见问题描述中的表格. 任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内. 插入的数字总数不超过4 000 000个,