bzoj3224 普通平衡树

bzoj3224 普通平衡树

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]

题解

  如题,随便用个平衡树维护即可。(我用的是Splay)

Code

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<cmath>
  7 using namespace std;
  8 #define ll long long
  9 #define REP(i,a,b) for(register int i=(a),_end_=(b);i<=_end_;i++)
 10 #define DREP(i,a,b) for(register int i=(a),_end_=(b);i>=_end_;i--)
 11 #define EREP(i,a) for(register int i=start[(a)];i;i=e[i].next)
 12 inline int read()
 13 {
 14     int sum=0,p=1;char ch=getchar();
 15     while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
 16     if(ch=='-')p=-1,ch=getchar();
 17     while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
 18     return sum*p;
 19 }
 20 
 21 const int maxn=3e5+20;
 22 
 23 struct node {
 24     int cnt,val,ch[2],fa,sz;//每个节点维护两个信息,该点所代表的值和以该点为根的树的节点个数,cnt表示是这个值的数的个数
 25 };
 26 node t[maxn];
 27 int n,root=0,sz;
 28 
 29 void init()
 30 {
 31     n=read();
 32 }
 33 
 34 void push_up(int u)//维护以u点为根的树的节点个数
 35 {
 36     t[u].sz=t[t[u].ch[0]].sz+t[t[u].ch[1]].sz+t[u].cnt;
 37 }
 38 
 39 void rotate(int x)
 40 {
 41     int y=t[x].fa,z=t[y].fa,k=t[y].ch[1]==x;
 42     t[z].ch[t[z].ch[1]==y]=x;t[x].fa=z;
 43     t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].fa=y;
 44     t[x].ch[k^1]=y;t[y].fa=x;push_up(y);push_up(x);
 45 }
 46 
 47 void Splay(int x,int goal)
 48 {
 49     while(t[x].fa!=goal)
 50     {
 51         int y=t[x].fa,z=t[y].fa;
 52         if(t[y].fa!=goal)
 53         {
 54             ((t[y].ch[0]==x)^(t[z].ch[0]==y))?rotate(x):rotate(y);
 55         }
 56         rotate(x);
 57     }
 58     if(!goal)root=x;
 59 }
 60 
 61 void newt(int fa,int id,int val)
 62 {
 63     t[id]={1,val,{0,0},fa,1};
 64 }
 65 
 66 void insert(int x)
 67 {
 68     int u=root,fa=0;
 69     while(u && t[u].val!=x){fa=u;u=t[u].ch[x>t[u].val];}
 70     if(u)t[u].cnt++;
 71     else
 72     {
 73         u=++sz;
 74         if(fa)t[fa].ch[x>t[fa].val]=u;
 75         newt(fa,sz,x);
 76     }
 77     Splay(u,0);
 78 }
 79 
 80 void Find(int x)
 81 {
 82     int u=root;if(!u)return;
 83     while(t[u].ch[x>t[u].val] && x!=t[u].val)
 84     {
 85         u=t[u].ch[x>t[u].val];
 86     }
 87     Splay(u,0);
 88 }
 89 
 90 int Nxt(int x,int f)//求前驱和后继
 91 {
 92     Find(x);
 93     int u=root;
 94     if((t[u].val>x && f)|| (t[u].val<x && !f))return u;
 95     u=t[u].ch[f];
 96     while(t[u].ch[f^1])u=t[u].ch[f^1];
 97     return u;
 98 }
 99 
100 void Del(int x)//找出前驱和后继后,把前驱变成根,后继变成根的右儿子,要删除的点就是后继的左儿子
101 {
102     int last=Nxt(x,0),next=Nxt(x,1);
103     Splay(last,0);Splay(next,last);
104     int del=t[next].ch[0];
105     if(t[del].cnt>1)t[del].cnt--,Splay(del,0);
106     else t[next].ch[0]=0;
107 }
108 
109 int kth(int x)
110 {
111     int u=root;
112     if(t[u].sz<x)return 0;
113     while(1)
114     {
115         int y=t[u].ch[0];
116         if(x>t[y].sz+t[u].cnt)
117         {
118             x-=t[y].sz+t[u].cnt;
119             u=t[u].ch[1];
120         }
121         else if(t[y].sz>=x)
122             u=y;
123         else
124             return t[u].val;
125     }
126 }
127 
128 void doing()
129 {
130     insert(-0x7fffffff); insert(0x7fffffff);//必须要在两边加个点,不然可能找不到前驱或后继
131     REP(i,1,n)
132     {
133         int opt=read(),x=read();
134         if(opt==1)
135         {
136             insert(x);
137         }
138         else if(opt==2)
139         {
140             Del(x);
141         }
142         else if(opt==3)
143         {
144             Find(x);
145             cout<<t[t[root].ch[0]].sz<<endl;//前面加了一个点,所以计算排名要减去1
146         }
147         else if(opt==4)
148         {
149             cout<<kth(x+1)<<endl;//同理,在查找排名时要加1
150         }
151         else if(opt==5)
152         {
153             cout<<t[Nxt(x,0)].val<<endl;
154         }else
155         {
156             cout<<t[Nxt(x,1)].val<<endl;
157         }
158     }
159 }
160 
161 int main()
162 {
163     init();
164     doing();
165     return 0;
166 }

  

原文地址:https://www.cnblogs.com/gzy-cjoier/p/7228662.html