P3369 【模板】普通平衡树

题目

题目

思路

因为Erase函数没加&,改了3H……
垂死病中惊坐起,小丑竟是我自己
code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
struct Treap{
 int l,r;//左右子编号 
 int v,d;//v权值(真),d随机值(旋转用) 
 int cnt,size;//cnt重复个数,size子树大小 
} a[100010];
int tot,root=1,n,inf=1e9,rank1,v;
int New()//新建节点 
{
 a[++tot].v=v;
 a[tot].d=rand();
 a[tot].cnt=1;
 a[tot].size=1;
 return tot;
}
void Up(int x)
{
 a[x].size=a[a[x].l].size+a[a[x].r].size+a[x].cnt;
 return; 
}
void Build()
{
 v=-inf;
 root=New();
 v=inf;
 a[root].r=New();
 //避免越界
 Up(root);
 return;
}
int GRBV(int x)//求排名 
{
 if (x==0) return -2;//未查询到结果
 if (v==a[x].v) return a[a[x].l].size+1;//返回排名
 if (v<a[x].v) return GRBV(a[x].l); 
 return GRBV(a[x].r)+a[a[x].l].size+a[x].cnt;//类似二分 
}
int GVBR(int x)//求值 
{
 if (x==0) return 1e9;//未查询到结果
 if (a[a[x].l].size>=rank1) return GVBR(a[x].l);//二分 
 if (a[a[x].l].size+a[x].cnt>=rank1) return a[x].v;//返回结果 
 rank1-=a[a[x].l].size+a[x].cnt;
 return GVBR(a[x].r);//二分 
}
void zig(int &x)//右旋(左节点变父节点) 
{
 int y=a[x].l;
 a[x].l=a[y].r,a[y].r=x,x=y;
 Up(a[x].r),Up(x);
 return;
}
void zag(int &x)//左旋(右节点变父节点) 
{
 int y=a[x].r;
 a[x].r=a[y].l,a[y].l=x,x=y;
 Up(a[x].l),Up(x);
 return;
}
void Insert(int &x)//插入 
{
 if (x==0)//新建节点 
 {
  x=New();
  return;
 }
 if (v==a[x].v)//已有节点,个数+1 
 {
  a[x].cnt++,Up(x);
  return;
 }
 if (v<a[x].v)//二分 
 {
  Insert(a[x].l);
  if (a[x].d<a[a[x].l].d) zig(x);
  Up(x);
  return;
 }
 Insert(a[x].r);
 if (a[x].d<a[a[x].r].d) zag(x);
 Up(x);
 return;
}
int GP()//求前缀 
{
 int ans,x=root;
 while (x)
 {
  if (v>a[x].v)
  {
   ans=a[x].v,x=a[x].r;
  }
  else x=a[x].l;
 }
 return ans;
}
int GN()//求后缀 
{
 int ans,x=root;
 while (x)
 {
  if (v<a[x].v)
  {
   ans=a[x].v,x=a[x].l;
  }
  else x=a[x].r;
 }
 return ans;
}
void Erase(int &x)//删除 
{
 if (x==0) return;
 if (v==a[x].v)
 {
  if (a[x].cnt>1)
  {
   a[x].cnt--,Up(x);
   return;//多个,删一个 
  }
  if (a[x].l||a[x].r)//有子节点
  {
   if (a[x].r==0||a[a[x].l].d>a[a[x].r].d) zig(x),Erase(a[x].r);
   else zag(x),Erase(a[x].l);//旋转,然后删除节点(保证平衡) 
   Up(x);
  }
  else x=0;
  return;
 }
 if (v<a[x].v)
 {
  Erase(a[x].l);
 }
 else
 {
  Erase(a[x].r);
 }//二分 
 Up(x);
 return;
}
int main()
{
 //srand(114514);
 Build();
 cin>>n;
 int o,x;
 while (n--)
 {
  cin>>o>>x;
  if (o==1)
  {
   v=x;
   Insert(root);
  }
  if (o==2)
  {
   v=x;
   Erase(root);
  }
  if (o==3)
  {
   v=x;
   cout<<GRBV(root)-1<<endl;
  }
  if (o==4)
  {
   rank1=x+1;
   cout<<GVBR(root)<<endl;
  }
  if (o==5)
  {
   v=x;
   cout<<GP()<<endl;
  }
  if (o==6)
  {
   v=x;
   cout<<GN()<<endl;
  }
 }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值