3224: Tyvj 1728 普通平衡树
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 3948 Solved: 1627
[Submit][Status][Discuss]
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每行输出一个数,表示对应答案
Sample Input
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
106465
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-1e7,1e7]
以下代码是模板式题解,并有详细注释。。。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstring> 7 #include<queue> 8 using namespace std; 9 struct splay 10 { 11 int data,lc,rc,fa; 12 int size;//子树的点,包括自己 13 }a[100005]; 14 15 int q,root=0,tot=0; 16 17 void update(int x){//算x点的size值 18 a[x].size=a[a[x].lc].size+a[a[x].rc].size+1;//注意:一定要+1,即算上自己本身 19 } 20 21 void r_rotate(int x){//让x右旋 22 /* 23 右旋: 24 条件:右旋出现在x,y之间,x是y的左儿子 25 目标:x变为父亲,y变为儿子(一定是右儿子) 26 步骤: 27 1.如果x有有儿子,使y的左儿子(原来是x)变成x的右儿子(现在x的右儿子是y) 28 2.x的父亲变成y原来的父亲,并更新父亲指针 29 3.更新x与y的父亲儿子指针和size值 30 */ 31 int y=a[x].fa;//y是x的父亲 32 //步骤1: 33 a[y].lc=a[x].rc;//换儿子 34 if(a[x].rc!=0)//如果x的原右儿子不为空: 35 a[a[x].rc].fa=y;//使x的原右儿子父亲为y 36 //步骤2: 37 a[x].fa=a[y].fa;//换父亲 38 if (y==a[a[y].fa].lc)//如果y是其父亲的左儿子 39 a[a[y].fa].lc=x; 40 else//如果y是其父亲的右儿子 41 a[a[y].fa].rc=x; 42 //步骤3: 43 a[y].fa=x; 44 a[x].rc=y;//注意:右旋y一定变成x的右儿子 45 update(y);//更新y的size 46 update(x);//更新x的size 47 } 48 void l_rotate(int x){//左旋方式同右旋 49 int y=a[x].fa; 50 a[y].rc=a[x].lc; 51 if (a[x].lc!=0) a[a[x].lc].fa=y; 52 a[x].fa=a[y].fa; 53 if (y==a[a[y].fa].lc) a[a[y].fa].lc=x; 54 else a[a[y].fa].rc=x; 55 a[y].fa=x; 56 a[x].lc=y; 57 update(y); 58 update(x); 59 } 60 void splay(int x,int s){//将x旋到s的下方 61 /**/ 62 while (a[x].fa!=s){ 63 if (x==a[a[x].fa].lc)//如果x是其父亲的左儿子 64 r_rotate(x);//右旋 65 else//如果x是其父亲的右儿子 66 l_rotate(x);//左旋 67 } 68 update(x);//旋之后更新x的size 69 if (s==0)//将x旋到0的下方,x变成了根 70 root=x; 71 } 72 73 int Search(int w){//要插入点的data 74 int p,x=root; 75 while(x){ 76 p=x; 77 //二叉搜索树性质:对于任意节点x,其左子树节点的data小于x的data 78 // 其右子树节点的data大于x的data 79 if (a[x].data>w)//当前节点data大于要插入的data,所以要插入的一定在左子树 80 x=a[x].lc; 81 82 else x=a[x].rc;//否则在右子树 83 } 84 return p; 85 } 86 87 void New_Node(int &x,int fa,int key){//对于一个新节点x,使其左右孩子都为0,父亲 88 //为fa,节点值为key 89 x=++tot;//使root=tot 90 a[x].lc=a[x].rc=0; 91 a[x].fa=fa; 92 a[x].data=key; 93 } 94 void Insert(int w)//插入操作 插入一个data为w的节点,使其满足搜索二叉树的性质 95 { 96 if (root==0)//说明没有根节点,插入根节点 97 { 98 New_Node(root,0,w); 99 return; 100 } 101 //如果不是根节点 102 int i=Search(w);//找到要插到的父亲节点 103 if (w<a[i].data)//要插入的节点的data比其父节点小,所以作为左而子 104 New_Node(a[i].lc,i,w); 105 //否则作为右儿子 106 else New_Node(a[i].rc,i,w); 107 108 splay(tot,0);//将当前新节点旋转至0的下方,即旋转至根(保证中序遍历不变) 109 } 110 int Get(int w){//寻找一个data为w的节点,利用二叉搜索树:右子树.data>节点.data>左子树.data 111 int x=root; 112 int ans=tot+1; 113 while(x!=0){ 114 if(a[x].data>w){ 115 x=a[x].lc; 116 continue; 117 } 118 if(a[x].data<w){ 119 x=a[x].rc; 120 continue; 121 } 122 if(a[x].data==w){ 123 ans=x; 124 x=a[x].lc; 125 } 126 } 127 if (ans==tot+1) return -1; 128 return ans; 129 } 130 131 int Getmax(int x){//返回以x为根的树的最大data的节点号 132 while(a[x].rc!=0) 133 x=a[x].rc; 134 return x; 135 } 136 137 int Getmin(int x){//返回以x为根的树的最小data的节点号 138 while(a[x].lc!=0) 139 x=a[x].lc; 140 return x; 141 } 142 143 int Getpre(int x){ 144 return Getmax(a[root].lc); 145 } 146 147 int Getne(int x){ 148 return Getmin(a[root].rc); 149 } 150 151 void Delet(int w){//删除操作 删除一个data为w的节点,使其满足搜索二叉树的性质 152 /* 153 步骤: 154 1.将要删除的节点移至根。 155 2.查找L的最大节点,此时,L的根没有右子树。 156 3.查找R的最小节点 157 4.删除根,剩下两个子树L(左子树)和R(右子树)。 158 使R成为L的根的右子树。 159 */ 160 // 步骤1: 161 int x=Get(w); 162 splay(x,0);//旋至根 163 //步骤2: 164 int pp=Getpre(x); 165 //步骤3: 166 int nn=Getne(x); 167 168 splay(pp,0);//把以x左孩子为根的最大值节点旋至树根 169 splay(nn,root);//把以x右孩子为根的最小值节点旋至树根下面 170 //步骤4: 171 int y=a[x].fa; 172 a[x].fa=0; 173 if (x==a[y].lc) a[y].lc=0; 174 else a[x].lc=0; 175 update(y); 176 update(root); 177 } 178 179 int Find(int w){//返回比w小的节点的个数 180 int x=Get(w); 181 splay(x,0); 182 return a[a[x].lc].size; 183 } 184 185 int Findkth(int x,int k){//在以x节点为根的树中,找第k大 186 int s=a[a[x].lc].size; 187 if (k==s+1) return a[x].data; 188 if (s>=k) return Findkth(a[x].lc,k); 189 else return Findkth(a[x].rc,k-s-1); 190 } 191 192 int getpre(int w){ 193 int y=Get(w); 194 Insert(w); 195 if (y!=-1) splay(y,0); 196 int ans=Getmax(a[root].lc); 197 Delet(w); 198 return a[ans].data; 199 } 200 201 int getne(int w){ 202 Insert(w); 203 int ans=Getmin(a[root].rc); 204 Delet(w); 205 return a[ans].data; 206 } 207 int main(){ 208 root=tot=0; 209 Insert(-50000000); 210 Insert(50000000); 211 scanf("%d",&q);//操作次数 212 while (q--){ 213 int x,k; 214 scanf("%d%d",&x,&k); 215 if (x==1) Insert(k); 216 else if (x==2) Delet(k); 217 else if (x==3) printf("%d\n",Find(k)); 218 else if (x==4) printf("%d\n",Findkth(root,k+1)); 219 else if (x==5) printf("%d\n",getpre(k)); 220 else if (x==6) printf("%d\n",getne(k)); 221 } 222 return 0; 223 }
时间: 2024-10-12 18:25:18