bzoj 3224: Tyvj 1728 普通平衡树 && loj 104 普通平衡树 (splay树)

题目链接:

https://www.lydsy.com/JudgeOnline/problem.php?id=3224

思路:

splay树模板题:

推荐博客:https://blog.csdn.net/clove_unique/article/details/50630280

b站上splay树的讲解视频也可以看下,讲的很好,推荐看完视频了解了splay的原理再写

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M = 1e5+10;
const int inf = 1<<30;
struct node{
    int fa,s[2],x,size,cnt;
}tr[M];
int top,root,n;
void pushup(int k){
     tr[k].size = tr[tr[k].s[0]].size+tr[tr[k].s[1]].size+tr[k].cnt;
}

void rotate(int k){
    int x = tr[k].fa,y = tr[x].fa,b=tr[x].s[1]==k;
    tr[y].s[tr[y].s[1]==x]=k;tr[k].fa=y;
    tr[x].s[b]=tr[k].s[b^1]; tr[tr[k].s[b^1]].fa=x;
    tr[k].s[b^1]=x; tr[x].fa = k;
    pushup(x); pushup(k);
}

void splay(int x,int go){   //伸展操作
     int y = tr[x].fa,z = tr[y].fa;
     for(;tr[x].fa^go;rotate(x)){
         y = tr[x].fa,z = tr[y].fa;
         if(z^go) (tr[y].s[0] == x)^(tr[z].s[0]==y)?rotate(x):rotate(y);
     }
     if(!go) root = x;
}

void insert(int x){  //插入操作
    int u = root,fa = 0;
    for(;u&&tr[u].x^x;u=tr[u].s[x>tr[u].x]) fa = u;
    if(u) tr[u].cnt++;  //若已经有这个数了,到cnt++即可
    else{  //新建一个节点
        u = ++top;
        if(fa) tr[fa].s[x>tr[fa].x] = u;
        tr[top].fa = fa;tr[top].x = x;tr[top].cnt = tr[top].size = 1;
    }
    splay(u,0); //splay 到根
}
//这个函数还有一个功能是把一个跟x不相隔仍荷属的数转移到根
int rank(int x){  //查找x的排名
    int u = root;
    if(!u) return 0;
    for(;tr[u].s[x>tr[u].x]&&x^tr[u].x;u=tr[u].s[x>tr[u].x]);
    splay(u,0);  //splay 到根
    return tr[tr[u].s[0]].size;
}
//求x的前驱后继
int next(int x,int f){  //f=0表示前驱,f=1表示后继,返回的是编号
    rank(x); //将与x不相隔任何数的数转移到根
    int u = root;
    if(tr[u].x>x&&f||tr[u].x<x&&!f) return u; //若已经是答案,则返回
    u = tr[u].s[f];
    while(tr[u].s[f^1]) u = tr[u].s[f^1];  //查找前驱时在左子树中查找最大值,后继反之
    return u;
}

void erase(int x){
    int up = next(x,1),lo = next(x,0),u; //得到前驱后继
    splay(lo,0); splay(up,lo);  //移成一个好局面
    u = tr[up].s[0];
    if(tr[u].cnt > 1){
        tr[u].cnt--;
        splay(u,0);
    }
    else {
        tr[up].s[0] = 0;
        pushup(up); pushup(lo);
    }
}

int find(int x){
    x++;
    int u = root,son;
    if(tr[u].size < x) return 0;  //没有这个数
    while(1){
        son = tr[u].s[0];
        if(tr[son].size >= x) u = son;
        else if(x>tr[son].size+tr[u].cnt)
            x -= tr[son].size + tr[u].cnt, u = tr[u].s[1];
        else break;
    }
    splay(u,0);
    return tr[u].x;
}

int main(){
    scanf("%d",&n);
    int op,x;
    insert(-inf); insert(inf);
    for(int i = 1;i <= n;i ++){
        scanf("%d%d",&op,&x);
        switch(op){
            case 1: insert(x);break;
            case 2: erase(x); break;
            case 3: printf("%d\n",rank(x));break;
            case 4: printf("%d\n",find(x)); break;
            case 5: printf("%d\n",tr[next(x,0)].x); break;
            case 6: printf("%d\n",tr[next(x,1)].x); break;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kls123/p/9426056.html

时间: 2024-10-11 23:16:12

bzoj 3224: Tyvj 1728 普通平衡树 && loj 104 普通平衡树 (splay树)的相关文章

bzoj 3224: Tyvj 1728 普通平衡树.

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

BZOJ 3224: Tyvj 1728 普通平衡树 treap

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

BZOJ 3224: Tyvj 1728 普通平衡树(BST)

treap,算是模板题了...我中间还一次交错题... -------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define rep(i,n) for(int i=0;i<n;

BZOJ 3224 Tyvj 1728 普通平衡树 | Splay 板子

下面给出Splay的实现方法(复杂度证明什么的知道是 nlogn 就可以啦) 首先对于一颗可爱的二叉查找树,是不能保证最坏nlogn的复杂度(可以想象把一个升序序列插入) 所以我们需要一些非常巧妙的旋转操作 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #define N 100010 6 #define which(x) (ls[fa[(x)

[bzoj] 3224 Tyvj 1728 普通平衡树 || 平衡树板子题

#!/bin/bash g++ make.cpp -o make -Wall g++ 1.cpp -o ac -Wall g++ sb.cpp -o sb -Wall while true; do ./make > 1.in ./ac < 1.in > 1.out ./sb < 1.in > sb.out if diff 1.out sb.out; then printf "AC!" else exit fi done 原文地址:https://www.c

BZOJ 题目3224: Tyvj 1728 普通平衡树(SBT)

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

3224: Tyvj 1728 普通平衡树

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

3224: Tyvj 1728 普通平衡树(新板子)

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

HYSBZ 3224 Tyvj 1728 普通平衡树 splay模版

先学了splay写的 以后有空再学treap和sbt版 参考: http://blog.csdn.net/clove_unique/article/details/50630280 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector>