ZJOI2006书架Treap做法

作为一个刚学Treap只会打板子的菜鸡,这个做法还参悟题解了一节课才参悟出来的,感觉这个方法很巧妙

变量解释

A[i]表示编号为i的书的优先级,优先级第k小就是从上向下数第k本书
树的节点Node.val表示优先级,也是平衡树排序的关键字
Node.num表示该节点对应书的编号

因为没有两个书的优先级是一样的,所以元素不重复,getrank函数好写些

五个操作

Top:删去原来该书的代表元素,把该书优先级改为当前最小(置顶)

Bottom:删去原来该书的代表元素,把该书优先级改为当前最大(置底)

Insert:把该书与目标书代表的两个元素先从Treap中删掉,然后交换优先级,再加入Treap

Ask:对于编号为S的书,输出A[S]的名次-1

Query:输出优先级第S个节点的编号


样例很舒适地过了,然后交上去

卧槽十分?考场凉凉?

然后对拍发现自己Del函数有个地方忘Update了


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls (T[rt].s[0])
#define rs (T[rt].s[1])
#define son (T[rt].s[d]) 
using namespace std;
int Num,Size,A[202020];
char ch[200];
struct Node{
	int s[2],num,val,rnd,siz;
	bool cmp(int x){
		if (x<val) return 0;
		return 1;
	}
	void NewNode(int x){
		val=x; rnd=rand(); num=Num; siz=1;
	}
}T[4002020];
bool Cmpson(int rt){
	if (T[rs].rnd<T[ls].rnd) return 1;
	return 0;
}
void update(int rt){
	T[rt].siz=T[ls].siz+T[rs].siz+1;
}
void Rotate(int &rt,int d){
	int t=T[rt].s[d];
	T[rt].s[d]=T[t].s[d^1];
	T[t].s[d^1]=rt;
	update(rt); update(t);
	rt=t;
}
void Insert(int &rt,int x){
	if (!rt){
		rt=++Size;
		T[rt].NewNode(x);
		return;
	}
	T[rt].siz++;
	int d=T[rt].cmp(x);
	Insert(son,x);
	if (T[son].rnd<T[rt].rnd) Rotate(rt,d);
}
void Del(int &rt,int x){
	int d;
	if (T[rt].val==x){
		if (ls*rs==0){
			rt=ls+rs;
			return;
		}
		d=Cmpson(rt);
		Rotate(rt,d); Del(T[rt].s[d^1],x);
		update(rt);//一遍交漏了这句 
		return;
	}
	d=T[rt].cmp(x);
	Del(son,x);
	update(rt);
}
int getrank(int rt,int x){
	if (x==T[rt].val) return T[ls].siz+1;
	if (T[rt].val>x) return getrank(ls,x);
	else return T[ls].siz+1+getrank(rs,x);
}
int Find(int rt,int x){
	if (T[ls].siz+1==x) return T[rt].num;
	if (T[ls].siz>=x) return Find(ls,x);
	else return Find(rs,x-T[ls].siz-1);
}
int main(){
	int rank,x,n,m,Min=1,Max,i,rt=0,t;
	scanf("%d %d",&n,&m);
	Max=n;
	for (i=1;i<=n;i++){
		scanf("%d",&Num);
		A[Num]=i;
		Insert(rt,i);
	}
	while (m--){
		cin>>ch;
		int i;
		scanf("%d",&Num);
		if (ch[0]=='T'){
			Del(rt,A[Num]);
			A[Num]=--Min;	
			Insert(rt,A[Num]);
			continue;
		}
		if (ch[0]=='B'){
			Del(rt,A[Num]);
			A[Num]=++Max;
			Insert(rt,A[Num]);
			continue;
		}
		if (ch[0]=='I'){
			scanf("%d",&t);
			if (!t) continue;
			rank=getrank(rt,A[Num]);
			x=Find(rt,rank+t);
			Del(rt,A[Num]); Del(rt,A[x]);
			swap(A[Num],A[x]);
			Insert(rt,A[Num]);
			Num=x; Insert(rt,A[Num]);
			continue;
		}
		if (ch[0]=='A')
			printf("%d\n",getrank(rt,A[Num])-1);
		else
			printf("%d\n",Find(rt,Num));
	}
	return 0;
}
//data1.in
/*8 8
1 2 3 4 5 6 7 8 
I 4 -1
B 7
Q 7
A 6
T 4
A 3
B 5
T 4
*/
//6 6 3
//std:8 5 3


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值