[CodeVs][1514][Treap][书架]


这道题我全网就看到了一个treap,QAQ


这道题有个难题,他每次是对一个编号的书进行操作,如果是对从左到右的一个排名的书进行操作还好办.....


因此在网上一位大神的代码帮助下,我发现,可以在外界对每一个书的编号搞一个指针,然后用get_rank函数来求出这本书的排名,然后就很好搞了。。。

get_rank 怎么写呢? 我们将当前节点往父亲爬,直到爬到根,如果当前节点是其父亲的右儿子,那么rank就加上父亲的左儿子的大小,再加上1(父亲的大小)

由于要往上爬,当然要记录父亲了,在update里维护一下就好。

上代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<string>
#include<cstdlib>
#include<cmath>
#include<cctype>

const int N = 8e4 + 9;

struct Treap {
	int id, size, hr;
	Treap *l, *r, *fa;
	Treap () {}
	Treap (int id, Treap *fl) : id(id),size(1),hr(rand()),l(fl),r(fl),fa(fl) {}
	void update () { size = l -> size + r -> size + 1; l -> fa = r -> fa = this; }
}*root, meme[N], *pool = meme, *Null;

Treap* newnode (int xxx) {
	return new (pool++) Treap (xxx, Null);
}

using std :: pair;
typedef pair <Treap*,Treap*> Droot; 

Droot Split (Treap *x,int k) {
	if(x == Null) return Droot (Null, Null);
	Droot y;
	if(x -> l -> size >= k) {
		y = Split (x -> l, k);
		x -> l = y . second;
		x -> update ();
		y . second = x;
	} else {
		y = Split (x -> r, k - x -> l -> size - 1);
		x -> r = y . first;
		x -> update ();
		y . first = x;
	}
	return y;
}

Treap* Merge (Treap *A,Treap *B) {
	if(A == Null) return B;
	if(B == Null) return A;
	if(A -> hr > B -> hr) {
	  B -> l = Merge (A, B -> l);
	  B -> update ();
	  return B;
	} else {
	  A -> r = Merge (A -> r, B);
	  A -> update (); 
	  return A;
	}
}


Treap *ptr[N];
int n,m,id[N];

Treap* Build () {
	static Treap *stk[N], *last, *x; int top = 0;
	for (int i = 1; i <= n; ++i) {
		last = Null; ptr[id[i]] = x = newnode (id[i]);
		while (top && x -> hr < stk[top] -> hr) {
			stk[top] -> update ();
			last = stk[top--];
		}
		if(top) stk[top] -> r = x,x -> fa = stk[top];
		x -> l = last; last -> fa = x;
		stk[++top] = x;
	}
	while (top) stk[top--] -> update ();
	return stk[1];
}

int get_rank (Treap *x) { // 有了getrank我们就可以搞事情了.... 
	int res = x -> l -> size;
	while (x -> fa != Null) {
		if (x == x -> fa -> r) res += x -> fa -> l -> size + 1;
		x = x -> fa;
	}
	return res;
}

void puton (int xxx, bool v) {
	static Droot clc1,clc2;
		int k = get_rank (ptr[xxx]);	
	clc1 = Split (root, k); clc2 = Split (clc1.second,1);
		if(v) root = Merge(Merge(clc2.first,clc1.first),clc2.second);
		else root = Merge (clc1.first,Merge(clc2.second,clc2.first));
}

void bookon (int xxx,int opt) {
	if(!opt) return ;
	static Droot clc1,clc2,clc3;
	int k = get_rank (ptr[xxx]);
	clc1 = Split (root, k);
	clc2 = Split (clc1.second, 1);
	if(opt == -1) clc1 = Split(clc1.first, clc1.first -> size - 1), root = Merge (Merge(clc1.first,clc2.first),Merge(clc1.second,clc2.second));
	else clc3 = Split(clc2.second, 1), root = Merge (Merge(clc1.first, clc3.first), Merge(clc2.first,clc3.second));
}

int getin () {
	int num = 0; char a; bool fl = false;
	for (a = getchar(); a < '0' || a > '9'; a = getchar()) if(a == '-') fl = true;
	for (; a >= '0' && a <= '9'; a = getchar()) num = (num << 3) + (num << 1) + a - '0';
	if(fl) num = -num;
	return num;
}

int rank (Treap *x, int k) {
	if (x -> l -> size >= k) return rank (x -> l, k);
	if (x -> l -> size + 1 == k) return x -> id;
	return rank (x -> r, k - x -> l -> size - 1);
}

char opt[23];
int x;

void Print (Treap *x) {
	if(x == Null) return ;
	Print (x -> l);
	printf("%d\n",x -> id);
	Print (x -> r);
}

bool it (Treap *xx) {
	if(xx == Null) return 0;
	bool ok = 0;
	ok |= it (xx -> l);
	ok |= it (xx -> r);
	return ok || xx->fa==Null || xx->fa->l==xx || xx->fa->r==xx;
}

int main () {
	freopen ("1514.in","r",stdin);
	freopen ("1514.out","w",stdout);
	
	Null = new Treap (); Null -> size = 0;
	scanf("%d%d",&n,&m);
	for (int i = 1; i <= n; ++i) id[i] = getin ();
	root = Build ();
	for (int i = 1; i <= m; ++i) {
		scanf("%s%d",opt,&x);
		if(opt[0] == 'T') puton (x, true);
		else if(opt[0] == 'B') puton (x, false);
		else if(opt[0] == 'I') bookon (x, getin());
		else if(opt[0] == 'A') printf ("%d\n",get_rank(ptr[x]));
		else printf ("%d\n",rank(root, x));
	}
	return 0;
}

That is all.Thank you for watching.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值