BZOJ3224 普通平衡树

本文介绍了一个普通平衡树(Treap)的数据结构实现,通过插入、删除等操作维护数值集合,并支持查询特定数值的排名、根据排名查找数值等功能。示例代码展示了如何构建平衡树并实现这些操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 20469  Solved: 9056
[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.每个数的数据范围:[-2e9,2e9]

 

 

解析:

    平衡树模板题,详细过程看代码。

 

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
using namespace std;

const int Max=101001;
const int INF=0x7fffffff;
int n,m,tot,root=1;
struct Treap {
	int l, r;    //左右子节点在数组中的下标 
	int val, data;   //节点关键码,权值 
	int cnt, size;   //副本数、子树大小(包括自身) 
}a[Max];

inline int get_int()         //读入优化 
{
   int x=0,f=1;
   char c;
   for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
   if(c=='-') {f=-1;c=getchar();};
   for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
   return x*f;
}

inline int NEW(int num)        //插入 
{
   a[++tot].val=num;
   a[tot].cnt=a[tot].size=1;
   a[tot].data=rand();
   return tot;
}

inline void update(int p)       //更新 
{
   a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt;
}

inline void build()//插入INF和-INF,避免出现找不到前驱或后继的情况 
{
   NEW(-INF);
   NEW(INF);
   a[1].r=2;
   update(root);
}

inline void zig(int &p)     //右旋 
{
   int q=a[p].l;
   a[p].l=a[q].r; a[q].r=p; p=q;
   update(a[p].r); update(p);
}

inline void zag(int &p)    //左旋 
{
   int q=a[p].r;
   a[p].r=a[q].l; a[q].l=p; p=q;
   update(a[p].l);update(p);
}

inline void Insert(int &p,int val)  //插入 
{
   if(p==0)
   {
   	 p=NEW(val);
   	 return;
   }
   if(val==a[p].val)
   {
   	 a[p].cnt++;
   	 update(p);
   	 return;
   }
   if(val < a[p].val)
   {
   	 Insert(a[p].l,val);
   	 if(a[p].data < a[a[p].l].data) zig(p);    //不满足堆性质,右旋 
   }
   else
   {
   	 Insert(a[p].r,val);
   	 if(a[p].data < a[a[p].r].data) zag(p);    //不满足堆性质,左旋 
   }
   update(p);
}

inline void Remove(int &p,int val)    //删除                               
{
   if(p==0) return;
   if(val==a[p].val)       //检索到了val 
   {
   	 if(a[p].cnt > 1)      //有重复,只用减少副本数 
   	 {
   	   a[p].cnt--;
   	   update(p);
   	   return;
   	 }
   	 if(a[p].l || a[p].r)     //不是叶子节点,向下旋 
   	 {
   	   if(a[p].r==0 || a[a[p].l].data > a[a[p].r].data)
   	   {
   	   	 zig(p);
   	   	 Remove(a[p].r,val);
   	   }
   	   else
   	   {
   	   	 zag(p);
   	   	 Remove(a[p].l,val);
   	   }
   	   update(p);
   	 }
   	 else p=0;        //是叶子节点,删除 
   	 return;
   }
   if(val < a[p].val) Remove(a[p].l,val);
   else Remove(a[p].r,val);
   update(p);
}

inline int GetRankByVal(int p,int val)    //查询该数是第几小的数 
{
   if(p==0) return 0;
   if(val==a[p].val) return a[a[p].l].size+1;
   if(val<a[p].val) return GetRankByVal(a[p].l,val);
   return a[a[p].l].size+a[p].cnt+GetRankByVal(a[p].r,val);
}

inline int GetValByRank(int p,int Rank)   //查询第几小的数是多少 
{
   if(p==0) return INF;
   if(a[a[p].l].size >= Rank) return GetValByRank(a[p].l,Rank);
   if(a[a[p].l].size + a[p].cnt >= Rank) return a[p].val;
   else return GetValByRank(a[p].r,Rank - a[p].cnt - a[a[p].l].size);
}

inline int GetPre(int val)     //寻找前驱 
{
   int ans=1,p=root;
   while(p)
   {
     if(a[p].val==val)
   	 {
   	   if(a[p].l)
   	   {
   	   	 p=a[p].l;
   	   	 while(a[p].r) p=a[p].r;    //从左子树一直向右走 
   	   	 ans=p;
   	   }
   	   break;
   	 }
   	 if(a[p].val>a[ans].val&&a[p].val<val) ans=p;
   	 if(a[p].val>val) p=a[p].l;
   	 else p=a[p].r;
   }
   return a[ans].val;
}

inline int GetNext(int val)    //寻找后继 
{
   int ans=2,p=root;
   while(p)
   {
   	 if(a[p].val==val)
   	 {
   	   if(a[p].r)
   	   {
   	   	 p=a[p].r;
   	   	 while(a[p].l) p=a[p].l;    //从右子树一直向左走
   	   	 ans=p;
   	   }
   	   break;
   	 }
   	 if(a[p].val<a[ans].val&&a[p].val>val) ans=p;
   	 if(a[p].val>val) p=a[p].l;
   	 else p=a[p].r;
   }
   return a[ans].val;
}

int main()
{
   //freopen("lx.in","r",stdin);
   //freopen("lx.out","w",stdout);

   n=get_int();
   build();
   for(int i=1;i<=n;i++)
   {
   	 int n=get_int(),x=get_int();
   	 switch(n)
   	 {
   	   case 1:
   	   	 Insert(root,x);
   	   	 break;
   	   case 2:
   	   	 Remove(root,x);
   	   	 break;
   	   case 3:
   	   	 cout<<GetRankByVal(root,x)-1<<"\n";//因为人为存入了-INF,不能将其算在内,所以-1. 
   	   	 break;
   	   case 4:
   	   	 cout<<GetValByRank(root,x+1)<<"\n";//同理 
   	   	 break;
   	   case 5:
   	   	 cout<<GetPre(x)<<"\n";
   	   	 break;
   	   case 6:
   	   	 cout<<GetNext(x)<<"\n";
   	   	 break;
   	 }
   }

   return 0;
}

 于是六个月后再看这个板子觉得太丑了,于是。。。

#include <bits/stdc++.h>
using namespace std;

const int inf=1e9;
const int Max=100005;
int n,m,ans,root=1,tot;
struct Treap{int l,r,cnt,size,num,data;};
Treap tree[Max];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}
inline void print(int x)
{
	if(x>9) print(x/10);
	putchar('0'+x%10);
}



inline int NEW(int x)
{
	tree[++tot].num=x;
    tree[tot].cnt=tree[tot].size=1;
    tree[tot].data=rand();
    return tot;
}

inline void update(int p)
{
	tree[p].size=tree[tree[p].l].size+tree[tree[p].r].size+tree[p].cnt;
}

inline void zig(int &p)
{
   int q=tree[p].l;
   tree[p].l=tree[q].r; tree[q].r=p; p=q;
   update(tree[p].r); update(p);
}
 
inline void zag(int &p) 
{
   int q=tree[p].r;
   tree[p].r=tree[q].l; tree[q].l=p; p=q;
   update(tree[p].l);update(p);
}

inline void build()
{
    NEW(-inf),NEW(inf);
    tree[1].r=2;
    update(root);
}

inline void Insert(int &p,int x)
{
	if(!p){p=NEW(x);return;}
	if(tree[p].num==x){tree[p].cnt++,update(p);return;}
	if(tree[p].num>x)
	{
	  Insert(tree[p].l,x);
	  if(tree[tree[p].l].data>tree[p].data) zig(p);
	}
	else
	{
	  Insert(tree[p].r,x);
	  if(tree[tree[p].r].data>tree[p].data) zag(p);
	}
	update(p);
}

inline void Remove(int &p,int x)
{
	if(!p) return;
	if(tree[p].num==x)
	{
	  if(tree[p].cnt>1) {tree[p].cnt--,update(p);return;}
	  if(tree[p].l||tree[p].r)
	  {
	 	if(!tree[p].r||tree[tree[p].l].data>tree[tree[p].r].data) zig(p),Remove(tree[p].r,x);
	 	else zag(p),Remove(tree[p].l,x);
	 	update(p);
	  }
	  else p=0;
	  return;
	}
	if(tree[p].num<x) Remove(tree[p].r,x);
	else Remove(tree[p].l,x);
	update(p);
}

inline int rank(int &p,int x)
{
	if(!p) return 0;
	if(tree[p].num==x) return tree[tree[p].l].size+1;
	if(tree[p].num<x) return tree[tree[p].l].size+tree[p].cnt+rank(tree[p].r,x);
	if(tree[p].num>x) return rank(tree[p].l,x);
}

inline int val(int &p,int x)
{
	if(!p) return inf;
	if(tree[tree[p].l].size>=x) return val(tree[p].l,x);
	if(tree[tree[p].l].size+tree[p].cnt>=x) return tree[p].num;
	return val(tree[p].r,x-tree[tree[p].l].size-tree[p].cnt);
}

inline int pre(int p,int x)
{
	if(!p) return -inf;
	if(tree[p].num<x) return max(pre(tree[p].r,x),tree[p].num);
	return pre(tree[p].l,x);
}

inline int nxt(int p,int x)
{
	if(!p) return inf;
	if(tree[p].num>x) return min(tree[p].num,nxt(tree[p].l,x));
	return nxt(tree[p].r,x);
}

int main()
{
	n=get_int();build();
	for(int i=1;i<=n;i++)
	{
	  int tag=get_int(),x=get_int();
	  switch(tag)
	  {
		case 1:
		  Insert(root,x);
		  break;
		case 2:
		  Remove(root,x);
		  break;
		case 3:
		  print(rank(root,x)-1),putchar('\n');
		  break;
		case 4:
		  print(val(root,x+1)),putchar('\n');
		  break;
		case 5:
		  print(pre(root,x)),putchar('\n');
		  break;
		case 6:
		  print(nxt(root,x)),putchar('\n');
		  break;
	  }
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值