luogu P3369 普通平衡树
Posted johnran
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P3369 普通平衡树相关的知识,希望对你有一定的参考价值。
主要是贴一个splay的模板:
#include<bits/stdc++.h>
using namespace std;
namespace splay{
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
const int N = 1000005;
const int inf = 2e9;
int ch[N][2],f[N],key[N],nums[N],sz[N];
int rt, nodeCnt;
void clearNode(int x){//删掉某一个节点
sz[x]=ch[x][0]=ch[x][1]=f[x]=key[x]=nums[x]=0;
}
bool getDir(int x){//右儿子返回1,否则返回0
return ch[f[x]][1]==x?1:0;
}
void update(int x){//这里是更新一下size
if(x){
sz[x]=nums[x];
if(ls(x))sz[x]+=sz[ls(x)];
if(rs(x))sz[x]+=sz[rs(x)];
}
}
void rot(int x){
int fa=f[x],gf=f[fa],ws=getDir(x),ws1=getDir(fa),w=ch[x][ws^1];
ch[fa][ws]=w;f[w]=fa;
ch[gf][ws1]=x;f[x]=gf;
ch[x][ws^1]=fa;f[fa]=x;
update(fa);update(x);
}
void Splay(int x, int goal=0){
while(f[x]!=goal){
int fa=f[x],gf=f[fa];
if(gf!=goal){
if(getDir(x)==getDir(fa))rot(fa);//三点一线先旋转fa
else rot(x);
}
rot(x);
}
if(!goal)rt=x;
}
void Find(int v){//有v的情况出现v,否则出现一个前驱或者后继
if(!rt)return;
int curNode=rt;
while(ch[curNode][v>key[curNode]]&&v!=key[curNode]){
curNode=ch[curNode][v>key[curNode]];
}
Splay(curNode,0);
}
void Insert(int v){
int curNode=rt,p=0;
while(curNode&&key[curNode]!=v){
p=curNode;
curNode=ch[curNode][v>key[curNode]];
}
if(curNode){
++nums[curNode];
}else{
curNode=++nodeCnt;
if(p)ch[p][v>key[p]]=curNode;
f[curNode]=p;
ch[curNode][0]=ch[curNode][1]=0;
nums[curNode]=sz[curNode]=1;
key[curNode]=v;
}
Splay(curNode,0);
}
int kth(int k){//第k大的节点,插入-inf和inf的情况下,传入k+1
int curNode=rt;
if(sz[curNode]<k)return 0;
while(1){
if(k<=sz[ls(curNode)]){
curNode=ls(curNode);
}else if(k>sz[ls(curNode)]+nums[curNode]){
k-=sz[ls(curNode)]+nums[curNode];
curNode=rs(curNode);
}else{
return curNode;
}
}
}
int Rank(int v){
Find(v);
if(key[rt]>=v)return sz[ls(rt)];
else return sz[ls(rt)]+nums[rt];
}
int Next(int x, int op){//op=0,前驱,op=1后继,均为节点
Find(x);
if(key[rt]<x&&op==0)return rt;
if(key[rt]>x&&op==1)return rt;
int curNode=ch[rt][op];
while(ch[curNode][op^1])curNode=ch[curNode][op^1];
return curNode;
}
void del(int x){//前驱到根,后继到右子节点,中间剩个x
int pre=Next(x,0);
int nxt=Next(x,1);
Splay(pre,0),Splay(nxt,pre);
int node=ch[nxt][0];
if(nums[node]>=2){
--nums[node];
Splay(node,0);
}
else{
ch[nxt][0]=0;
}
}
void init(){
Insert(inf);
Insert(-inf);
}
};
inline int read(){
int res=0, f=1;char ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){res=res*10+ch-‘0‘;ch=getchar();}
return res*f;
}
int main(){
// freopen("P3369_6.in","r",stdin);
// freopen("stdout.txt","w",stdout);
int q=read();
splay::init();
while(q--){
int opt=read();
if(opt==1){
splay::Insert(read());
}else if(opt==2){
splay::del(read());
}else if(opt==3){
cout<<splay::Rank(read())<<endl;
}else if(opt==4){
cout<<splay::key[splay::kth(read()+1)]<<endl;
}else if(opt==5){
cout<<splay::key[splay::Next(read(),0)]<<endl;
}else{
cout<<splay::key[splay::Next(read(),1)]<<endl;
}
}
return 0;
}
以上是关于luogu P3369 普通平衡树的主要内容,如果未能解决你的问题,请参考以下文章
luogu P3369 模板普通平衡树(Treap/SBT)
红黑树 ------ luogu P3369 模板普通平衡树(Treap/SBT)
替罪羊树 ------ luogu P3369 模板普通平衡树(Treap/SBT)