【洛谷P3369】 (模板)普通平衡树
https://www.luogu.org/problemnew/show/P3369
Splay模板
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 #define MAXN 100010 5 int n,sons[MAXN][2],f[MAXN],size[MAXN],cnt[MAXN],value[MAXN],root,Size; 6 inline int read(){ //快读 7 int x=0,ff=1; char c=getchar(); 8 while(c<'0'||c>'9') { if(c=='-') ff=-1; c=getchar(); } 9 while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); } 10 return x*ff; 11 } 12 inline void clear(int x){ //清除节点x 13 f[x]=sons[x][0]=sons[x][1]=size[x]=cnt[x]=value[x]=0; 14 } 15 inline int get_w(int p){ 16 return sons[f[p]][1]==p; 17 } 18 inline void update(int p){ 19 if(p){ 20 size[p]=cnt[p]; 21 if(sons[p][0]) size[p]+=size[sons[p][0]]; 22 if(sons[p][1]) size[p]+=size[sons[p][1]]; 23 } 24 } 25 inline void rotate(int x){ //旋转节点x 26 int fa=f[x],gfa=f[f[x]],ws=get_w(x); 27 sons[fa][ws]=sons[x][ws^1]; //father与son 28 f[sons[fa][ws]]=fa; 29 f[fa]=x; //father与x 30 sons[x][ws^1]=fa; 31 f[x]=gfa; //x与grandfather 32 if(gfa) sons[gfa][sons[gfa][1]==fa]=x; 33 update(x); 34 update(fa); 35 } 36 inline void Splay(int x){ //将x旋到root 37 for(int fa;fa=f[x];rotate(x)) 38 if(f[fa]) 39 rotate(get_w(x)==get_w(fa)?fa:x); //若x,father,grandfather三个节点呈一条直线,就旋中间的节点 40 root=x; 41 } 42 void insert(int x){ //插入节点 43 if(!root){ //如果树为空 44 Size++; 45 f[Size]=sons[Size][0]=sons[Size][1]=0; 46 size[Size]=cnt[Size]=1; 47 value[Size]=x; 48 root=Size; 49 return; 50 } 51 int now=root,fa=0; 52 while(1){ 53 if(value[now]==x){ //如果已有的节点值=x 54 cnt[now]++; //该节点数量+1 55 update(now); 56 update(fa); 57 Splay(now); //旋到root,维护平衡树 58 return; 59 } 60 fa=now; 61 now=sons[now][x>value[now]]; 62 if(!now){ 如果旋到叶子节点,新开一个点 63 Size++; 64 sons[Size][0]=sons[Size][1]=0; 65 f[Size]=fa; 66 size[Size]=cnt[Size]=1; 67 value[Size]=x; 68 sons[fa][value[fa]<x]=Size; 69 update(fa); 70 Splay(Size); 71 return; 72 } 73 } 74 } 75 int find_num(int x){ //找大小顺序为x的节点的值 76 int now=root; 77 while(1){ 78 if(sons[now][0]&&x<=size[sons[now][0]]) now=sons[now][0]; //左子树大小>x,则向左子树查询 79 else{ 80 int temp=(sons[now][0]?size[sons[now][0]]:0)+cnt[now]; 81 if(x<=temp) return value[now]; //x包含在cnt[now]中 82 x-=temp; 83 now=sons[now][1]; 84 } 85 } 86 } 87 int find_rank(int x){ //查询值为x的点的大小编号 88 int now=root,ans=0; 89 while(1){ 90 if(x<value[now]) now=sons[now][0]; 91 else{ 92 ans+=sons[now][0]?size[sons[now][0]]:0; 93 if(x==value[now]){ 94 Splay(now); 95 return ans+1; 96 } 97 ans+=cnt[now]; 98 now=sons[now][1]; 99 } 100 } 101 } 102 inline int find_pre(){ //root的前驱即为左子树中最靠右的点 103 int now=sons[root][0]; 104 while(sons[now][1]) now=sons[now][1]; 105 return now; 106 } 107 inline int find_suf(){ 108 int now=sons[root][1]; 109 while(sons[now][0]) now=sons[now][0]; 110 return now; 111 } 112 void delete_node(int x){ //删除节点x 113 find_rank(x); //将x旋上去 114 if(cnt[root]>1){ 115 cnt[root]--; 116 update(root); 117 return; 118 } 119 if(!sons[root][1]&&!sons[root][0]){ 120 clear(root); root=0; return; 121 } 122 if(!sons[root][1]){ 123 int last=root; 124 root=sons[root][0]; 125 f[root]=0; 126 clear(last); 127 return; 128 } 129 if(!sons[root][0]){ 130 int last=root; 131 root=sons[root][1]; 132 f[root]=0; 133 clear(last); 134 return; 135 } 136 int last=root,pre=find_pre(); //将前驱旋上去,此时x为pre的右儿子,直接删除即可(类似于链表) 137 Splay(pre); 138 sons[root][1]=sons[last][1]; 139 f[sons[last][1]]=root; 140 clear(last); 141 update(root); 142 } 143 int main() 144 { 145 n=read(); 146 int opt,x; 147 while(n--){ 148 opt=read(); x=read(); 149 switch(opt){ 150 case 1: insert(x); break; 151 case 2: delete_node(x); break; 152 case 3: printf("%d\n",find_rank(x)); break; 153 case 4: printf("%d\n",find_num(x)); break; 154 case 5: insert(x);printf("%d\n",value[find_pre()]);delete_node(x); break; 155 case 6: insert(x);printf("%d\n",value[find_suf()]);delete_node(x); break; 156 } 157 } 158 return 0; 159 }