BZOJ 1861: [Zjoi2006]Book 书架

本文详细介绍了如何使用Splay树解决特定操作问题,包括Top、Bottom、Insert、Ask和Query操作。通过代码实现展示了Splay树在复杂操作中的应用,提供了深入的技术洞察。

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

题目地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1861


题目大意:维护5个操作,具体详见原题(Charlie Pan表示博客写累了~)


算法讨论:

        Splay题。

        Part I 显然Top和Bottom操作是对称的,我们只需将节点旋转到Root后将左右儿子合并即可。

        Part II Insert操作略麻烦……

                我的做法是将左/右子树的最大/小值插入到右/左子树中。

                具体做法还是利用了Splay操作。

                至于其他大神的做法比较神奇,大家可以自行Baidu/Google。

        Part III Ask和Query操作时Splay的基本操作,就不一一赘述了。


Code:

/*
 * Problem:1861
 * Author:PYC
 */

#include <cstdio>
#include <algorithm>

#define maxn 800000

using namespace std;

char ch;
int n,m,root,a[maxn+1];

struct node{
	int l,r,fa,sz;
}tree[maxn+1];

char getopt(){
	while (ch!='T' && ch!='B' && ch!='I' && ch!='A' && ch!='Q') ch=getchar();
	return ch;
}

int getint(){
	while (ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
	int x=0;
	bool f=0;
	if (ch=='-') f=1,ch=getchar();
	while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
	if (f) x=-x;
	return x;
}

void up(int rt){
	tree[rt].sz=tree[tree[rt].l].sz+tree[tree[rt].r].sz+1;
}

void build(int &rt,int l,int r){
	int mid=(l+r)/2;
	rt=a[mid];
	tree[rt].sz=r-l+1;
	if (mid-l) build(tree[rt].l,l,mid-1),tree[tree[rt].l].fa=rt;
	if (r-mid) build(tree[rt].r,mid+1,r),tree[tree[rt].r].fa=rt;
}

int min_node(int rt){
	if (!tree[rt].l) return rt;
	return min_node(tree[rt].l);
}

int max_node(int rt){
	if (!tree[rt].r) return rt;
	return max_node(tree[rt].r);
}

void zig(int rt){
	int t=tree[rt].l;
	tree[rt].l=tree[t].r;
	tree[t].r=rt;
	tree[t].fa=tree[rt].fa;
	tree[rt].fa=t;
	tree[tree[rt].l].fa=rt;
	if (rt==tree[tree[t].fa].l) tree[tree[t].fa].l=t;else tree[tree[t].fa].r=t;
	up(rt);
	up(t);
}

void zag(int rt){
	int t=tree[rt].r;
	tree[rt].r=tree[t].l;
	tree[t].l=rt;
	tree[t].fa=tree[rt].fa;
	tree[rt].fa=t;
	tree[tree[rt].r].fa=rt;
	if (rt==tree[tree[t].fa].l) tree[tree[t].fa].l=t;else tree[tree[t].fa].r=t;
	up(rt);
	up(t);
}

void splay(int x,int &rt){
	int fa=tree[rt].fa;
	while (tree[x].fa!=fa){
		int y=tree[x].fa,z=tree[y].fa;
		if (z==fa) if (x==tree[y].l) zig(y);else zag(y);
		else if (y==tree[z].l)
			if (x==tree[y].l) zig(z),zig(y);else zag(y),zig(z);
		else if (x==tree[y].r) zag(z),zag(y);else zig(y),zag(z);
	}
	rt=x;
}

void top(int x){
	splay(x,root);
	if (tree[root].r){
		splay(min_node(tree[root].r),tree[root].r);
		tree[tree[root].r].l=tree[root].l;
		tree[tree[root].l].fa=tree[root].r;
		tree[root].l=0;
	}
	else{
		tree[root].r=tree[root].l;
		tree[root].l=0;
	}
	up(tree[root].r);
	up(root);
}

void bottom(int x){
	splay(x,root);
	if (tree[root].l){
		splay(max_node(tree[root].l),tree[root].l);
		tree[tree[root].l].r=tree[root].r;
		tree[tree[root].r].fa=tree[root].l;
		tree[root].r=0;
	}
	else{
		tree[root].l=tree[root].r;
		tree[root].r=0;
	}
	up(tree[root].l);
	up(root);
}

void insert(int x,int mode){
	if (!mode) return;
	splay(x,root);
	if (!tree[root].l && !tree[root].r) return;
	if (tree[root].l) splay(max_node(tree[root].l),tree[root].l);
	if (tree[root].r) splay(min_node(tree[root].r),tree[root].r);
	if (mode==1){
		if (tree[root].l){
			int rr=tree[tree[root].r].r;
			tree[tree[root].r].r=0;
			tree[tree[root].r].sz=1;
			tree[tree[root].l].r=tree[root].r;
			tree[tree[root].r].fa=tree[root].l;
			tree[root].r=rr;
			tree[tree[root].r].fa=root;
		}
		else{
			int rr=tree[tree[root].r].r;
			tree[tree[root].r].r=0;
			tree[tree[root].r].sz=1;
			tree[root].l=tree[root].r;
			tree[root].r=rr;
			tree[tree[root].r].fa=root;
		}
		up(tree[root].l);
		up(root);
	}
	if (mode==-1){
		if (tree[root].r){ 
			int ll=tree[tree[root].l].l;
			tree[tree[root].l].l=0;
			tree[tree[root].l].sz=1;
			tree[tree[root].r].l=tree[root].l;
			tree[tree[root].l].fa=tree[root].r;
			tree[root].l=ll;
			tree[tree[root].l].fa=root;
		}
		else{
			int ll=tree[tree[root].l].l;
			tree[tree[root].l].l=0;
			tree[tree[root].l].sz=1;
			tree[root].r=tree[root].l;
			tree[root].l=ll;
			tree[tree[root].l].fa=root;
		}
		up(tree[root].r);
		up(root);
	}
}

int ask(int x){
	splay(x,root);
	return tree[tree[root].l].sz;
}

int query(int rt,int x){
	if (x==tree[tree[rt].l].sz+1) return rt;
	if (x<tree[tree[rt].l].sz+1) return query(tree[rt].l,x);
	if (x>tree[tree[rt].l].sz+1) return query(tree[rt].r,x-tree[tree[rt].l].sz-1);
}

int main(){
	n=getint(),m=getint();
	for (int i=1;i<=n;++i) a[i]=getint();
	build(root,1,n);
	for (int i=1;i<=m;++i){
		char opt=getopt();
		int x=getint();
		if (opt=='T') top(x);
		if (opt=='B') bottom(x);
		if (opt=='I'){int y=getint();insert(x,y);}
		if (opt=='A') printf("%d\n",ask(x));
		if (opt=='Q') printf("%d\n",query(root,x));
	}
	return 0;
}

By Charlie Pan

Mar 4,2014

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值