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)]]==(x))
  7 typedef long long ll;
  8 using namespace std;
  9 int n,root,idx,val[N],fa[N],ls[N],rs[N],sze[N],cnt[N];
 10 int read()
 11 {
 12     int ret=0,neg=1;
 13     char j=getchar();
 14     for (;j>‘9‘ || j<‘0‘;j=getchar())
 15     if (j==‘-‘) neg=-1;
 16     for (;j>=‘0‘ && j<=‘9‘;j=getchar())
 17     ret=ret*10+j-‘0‘;
 18     return ret*neg;
 19 }
 20 void upt(int x)//更新子树大小
 21 {
 22     sze[x]=sze[ls[x]]+sze[rs[x]]+cnt[x];
 23 }
 24 void rotate(int x)//旋转操作
 25 {
 26     //y是x父亲,z是y父亲,b是y的另一个儿子
 27     int y=fa[x],z=fa[y],b=which(x)?rs[x]:ls[x],dir=which(y);
 28     which(x)?(rs[x]=y,ls[y]=b):(ls[x]=y,rs[y]=b);
 29     fa[y]=x,fa[b]=y,fa[x]=z;
 30     if (z) dir?ls[z]=x:rs[z]=x;
 31     upt(y),upt(x);//更新大小
 32 }
 33 void splay(int x)//把x旋转至根节点
 34 {
 35     //为了让树平衡,如果x和父亲同向,转fa[x]染红转x
 36     //否则转两次x
 37     while (fa[x])
 38     {
 39     if (fa[fa[x]])
 40         if (which(x)==which(fa[x])) rotate(fa[x]);
 41         else rotate(x);
 42     rotate(x);
 43     }
 44     root=x;//现在x是根了
 45 }
 46 int getmin(int x)//找以x为根子树最小值节点编号
 47 {
 48     while (ls[x]) x=ls[x];
 49     return x;
 50 }
 51 int getmax(int x)//找以x为根子树最大值节点编号
 52 {
 53     while (rs[x]) x=rs[x];
 54     return x;
 55 }
 56 int find(int x)//找值为x的节点没有返回0
 57 {
 58     int cur=root,last=0;
 59     while (cur && val[cur]!=x)
 60     {
 61     last=cur;
 62     if (x<val[cur]) cur=ls[cur];
 63     else cur=rs[cur];
 64     }
 65     return cur?cur:last;
 66 }
 67 void insert(int x)//插入x
 68 {
 69     int cur=find(x);//找到
 70     //如果已经存在x,把x++后splay成根节点
 71     if (cur && val[cur]==x) return (void)(cnt[cur]++,sze[cur]++,splay(cur));
 72     //如果不存在x就创造一个,然后splay
 73     val[++idx]=x,fa[idx]=cur,cnt[idx]=sze[idx]=1;
 74     if (cur) x<val[cur]?ls[cur]=idx:rs[cur]=idx;
 75     splay(idx);
 76 }
 77 void erase(int x)//删除值为x的节点
 78 {
 79     int cur=find(x);//保证存在
 80     splay(cur);//先把x转到根
 81     //如果x个数大于1,直接删掉就好
 82     if (cnt[cur]>1) cnt[cur]--,sze[cur]--;
 83     //如果有一个儿子节点为空,直接让另一个为根,如果都是空就说明树为空
 84     else if (!ls[cur] || !rs[cur]) root=ls[cur]+rs[cur],fa[root]=0;
 85     else
 86     {
 87     fa[ls[cur]]=0;//x的左儿子没爸爸了
 88     int u=getmax(ls[cur]);//让左子树最大值节点当新根节点,右子树的根节点是新根节点的右儿子
 89     splay(u);
 90     rs[u]=rs[cur],fa[rs[cur]]=u;
 91     upt(u);
 92     }
 93 }
 94 int getkth(int k)//寻找第k大,比较easy
 95 {
 96     int cur=root;
 97     while (cur)
 98     {
 99     if (sze[ls[cur]]>=k) cur=ls[cur];
100     else if (sze[ls[cur]]+cnt[cur]>=k) return val[cur];
101     else k-=sze[ls[cur]]+cnt[cur],cur=rs[cur];
102     }
103     return val[cur];
104 }
105 int getrank(int x)//询问x排名
106 {
107     int cur=find(x);
108     splay(cur);
109     return sze[ls[cur]]+1;
110 }
111 int getpre(int x)//找前驱
112 {
113     int cur=find(x);
114     if (val[cur]<x) return val[cur];
115     splay(cur);
116     return val[getmax(ls[cur])];
117 }
118 int getnxt(int x)//找后继
119 {
120     int cur=find(x);
121     if (val[cur]>x) return val[cur];
122     splay(cur);
123     return val[getmin(rs[cur])];
124 }
125 int main()
126 {
127     n=read();
128     for (int i=1,op,x;i<=n;i++)
129     {
130     op=read(),x=read();
131     if (op==1) insert(x);
132     if (op==2) erase(x);
133     if (op==3) printf("%d\n",getrank(x));
134     if (op==4) printf("%d\n",getkth(x));
135     if (op==5) printf("%d\n",getpre(x));
136     if (op==6) printf("%d\n",getnxt(x));
137     }
138     return 0;
139 }

原文地址:https://www.cnblogs.com/mrsheep/p/8110483.html

时间: 2024-08-07 19:49:54

BZOJ 3224 Tyvj 1728 普通平衡树 | 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 普通平衡树 &amp;&amp; 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 lo

[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

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>

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的前驱(前驱定义为

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,且最大的数)