【luogu3369】【模板】普通平衡树 [平衡树]

luogu3369

看的是洛谷日报上的教程  结果因为求第k大时那个判断就出了错导致时间超限 惨烈

 

然后还要注意开始要插入一个极大值和极小值

  1 /*
  2 id:gww
  3 language:C--
  4    
  5 */
  6 #include<bits/stdc++.h>
  7 using namespace std;
  8 const int N=200005;
  9 int ch[N][2],val[N],cnt[N],par[N],size[N];
 10 int root,ncnt=0;
 11 //0 1代表 x的左 右儿子 val[x] x存储的值 
 12 //cnt[x] x存储的重复权值的个数 par[x]代表 x的父节点 
 13 //size[x]代表 x子树下的储存的权值数(包括重复权值)
 14 inline int rd()
 15 {
 16     int x=0,w=0;char ch=0;
 17     while(!isdigit(ch)) w|=ch=='-',ch=getchar();
 18     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
 19     return w?-x:x;
 20 }
 21 
 22 void pushup(int x) {size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];}//更新size数组 
 23 bool chk(int x) {return ch[par[x]][1]==x;}//判断x位于它父亲的方向 
 24 
 25 void rotate(int x)//旋转 将被指定节点向上移动一级 
 26 {
 27     int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
 28     ch[y][k]=w;par[w]=y; 
 29 //父节点连向需旋转的该子节点的方向的边连向该子节点位于其父节点方向的反方向的节点
 30     ch[z][chk(y)]=x;par[x]=z;
 31 //爷爷节点连向父节点的边连向需旋转的该节点
 32     ch[x][k^1]=y;par[y]=x;
 33 //需旋转的该节点连向该子节点位于其父节点方向的反方向的子节点的边连向其父节点
 34     pushup(y);pushup(x);
 35 }
 36 
 37 void splay(int x,int goal=0)//伸展 
 38 {
 39     while(par[x]!=goal)
 40     {
 41         int y=par[x],z=par[y];
 42         if(z!=goal)
 43         {
 44             if(chk(x)==chk(y)) rotate(y);//三点一线 转父亲
 45             else rotate(x);
 46         }
 47         rotate(x); 
 48     }
 49     if(!goal) root=x;
 50 }
 51 
 52 void find(int x)//将最大的小于等于x的数所在的节点splay到根
 53 {
 54 //    if(!root) return;
 55     int cur=root;
 56     while(val[cur]!=x&&ch[cur][x>val[cur]]) {cur=ch[cur][x>val[cur]];}
 57     splay(cur);
 58 }
 59 
 60 void insert(int x)//插入 
 61 {
 62     int cur=root,p=0;//从根节点开始
 63     while(val[cur]!=x&&cur) {p=cur;cur=ch[cur][x>val[cur]];} //不存在 新建节点并与父节点连边
 64     if(cur) cnt[cur]++;//节点存在则直接自增cnt的值
 65     else//新建节点时可能会拉出一条链,
 66     {
 67         cur=++ncnt;
 68         if(p) ch[p][x>val[p]]=cur;
 69         par[cur]=p;val[cur]=x;
 70         ch[cur][0]=ch[cur][1]=0;
 71         size[cur]=cnt[cur]=1;
 72     }
 73     splay(cur);//所以新建节点后需要将该节点splay到根节点
 74 }
 75 
 76 int kth(int k)
 77 {
 78     int cur=root;
 79     while(1)
 80     {
 81         if (ch[cur][0] && k <= size[ch[cur][0]]) {cur = ch[cur][0];}
 82         else if (k > size[ch[cur][0]] + cnt[cur]) 
 83         {
 84             k-=size[ch[cur][0]]+cnt[cur];
 85             cur=ch[cur][1];
 86         }
 87         else {return cur;}
 88     }
 89 }
 90 
 91 int pre(int x)//前驱 小于这个值并且最接近这个值的元素值
 92 {
 93     find(x);//先初始化一个最值
 94     if(val[root]<x) return root;
 95     int cur=ch[root][0];//向下走 
 96     while(ch[cur][1]) cur=ch[cur][1];
 97     return cur; 
 98 }
 99 int succ(int x)//后继 大于这个值并且最接近这个值的元素值 
100 {
101     find(x);//先初始化一个最值
102     if(val[root]>x) return root;
103     int cur=ch[root][1];//向下走 
104     while(ch[cur][0]) cur=ch[cur][0];
105     return cur; 
106  } 
107 
108 void remove(int x)
109 {//把前驱splay到根,后继splay到前驱的右儿子,那么后继的左儿子就是要删除的点
110     int last=pre(x),nxt=succ(x);
111     splay(last);splay(nxt,last);
112     int del=ch[nxt][0];
113     if(cnt[del]>1) {cnt[del]--;splay(del);}
114     else {ch[nxt][0]=0;}
115 }
116 
117 int getrank(int x)
118 {
119     find(x);
120     return size[ch[root][0]];
121 }
122 
123 int main()
124 {
125     int t=rd();
126     insert(1e9);
127     insert(-1e9);
128     while(t--)
129     {
130         int opt=rd(),x=rd();
131         if(opt==1) insert(x);
132         if(opt==2) remove(x);
133         if(opt==3) printf("%d\n",getrank(x));
134         if(opt==4) printf("%d\n",val[kth(x+1)]);
135         if(opt==5) printf("%d\n",val[pre(x)]);
136         if(opt==6) printf("%d\n",val[succ(x)]);
137     }
138     return 0;
139 }
100昏

 something from yyb

转载于:https://www.cnblogs.com/lxyyyy/p/10383932.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值