洛谷P2596 [ZJOI2006]书架

题目

https://www.luogu.com.cn/problem/P2596

思路

这显然是一道数据结构题。

观察一下要求支持的操作,要是没有top和bottom操作就好了诶,开一个类似map的东西就可以了,然而这两个操作导致了剩余书本的编号和排名的映射关系都发生了变化。

所以,我们需要一个暴力的数据结构维护书本之间的位置关系,并支持随时插入和删除,那自然就想到splay啦。

值得注意的是结点i本身就表示编号为i的书,所以并不需要结点权值,建树的时候按照排名顺序依次插入树的末尾即可。

代码

#include<cstdlib>
#include<algorithm>
#define maxn (int)(8e4+10)
using namespace std;
int a[maxn],n,m;
struct SplayTree{
	int root,cnt,lc[maxn],rc[maxn],fa[maxn],sz[maxn],rk[maxn];
	private:
		void update(int x){
			if(x) sz[x]=sz[lc[x]]+sz[rc[x]]+1;
			return;
		}
		void zig(int x){
			int y=fa[x];
			fa[x]=fa[y];
			if(fa[y])
				if(lc[fa[y]]==y) lc[fa[y]]=x;
				else rc[fa[y]]=x;
			int z=rc[x];
			if(z) fa[z]=y;
			lc[y]=z;
			fa[y]=x;
			rc[x]=y;
			update(y);update(x);
			return;
		}
		void zag(int x){
			int y=fa[x];
			fa[x]=fa[y];
			if(fa[y])
				if(lc[fa[y]]==y) lc[fa[y]]=x;
				else rc[fa[y]]=x;
			int z=lc[x];
			if(z) fa[z]=y;
			rc[y]=z;
			fa[y]=x;
			lc[x]=y;
			update(y);update(x);
			return;
		}
		void splay(int x,int r){
			while(fa[x]!=r){
				int y=fa[x],z=fa[y];
				if(z==r){
					if(lc[y]==x) zig(x);
					else zag(x);
				}
				else{
					if(lc[y]==x&&lc[z]==y){
						zig(y);zig(x);
					}
					else if(rc[y]==x&&rc[z]==y){
						zag(y);zag(x);
					}
					else if(lc[y]==x&&rc[z]==y){
						zig(x);zag(x);
					}
					else{
						zag(x);zig(x);
					}
				}
			}
			if(!r) root=x;
			return;
		}
		int front(int x){
			while(lc[x]) x=lc[x];
			return x;
		}
		int rear(int x){
			while(rc[x]) x=rc[x];
			return x;
		}
		void push_front(int now,int x){
			if(!now){
				root=x;
				return;
			}
			if(lc[now]) push_front(lc[now],x);
			else{
				lc[now]=x;
				fa[x]=now;
			}
			update(now);
			return;
		}
		void push_rear(int now,int x){
			if(!now){
				root=x;
				return;
			}
			if(rc[now]) push_rear(rc[now],x);
			else{
				rc[now]=x;
				fa[x]=now;
			}
			update(now);
			return;
		}
		void exchange(int x,int y){
			if(lc[x]==y){
				rc[y]=rc[x];
				rc[x]=0;
				lc[x]=lc[y];
				lc[y]=x;
				fa[x]=y;fa[y]=0;
				if(lc[x]) fa[lc[x]]=x;
				if(rc[y]) fa[rc[y]]=y;
			}
			else{
				lc[y]=lc[x];
				lc[x]=0;
				rc[x]=rc[y];
				rc[y]=x;
				fa[x]=y;fa[y]=0;
				if(rc[x]) fa[rc[x]]=x;
				if(lc[y]) fa[lc[y]]=y;
			}
			update(x);update(y);
			return;
		}
		int get_id(int x,int k){
			int t=sz[lc[x]];
			if(t+1==k) return x;
			if(t+1<k) return get_id(rc[x],k-t-1);
			else return get_id(lc[x],k);
		}
	public:
		void build(){
			root=cnt=0;
			int i;
			for(i=1;i<=n;i++){
				lc[i]=rc[i]=fa[i]=0;
				sz[i]=1;
			}
			for(i=1;i<=n;i++){
				push_rear(root,a[i]);
				splay(a[i],0);
			}
			return;
		}
		void top(int x){
			splay(x,0);
			if(!lc[x]) return;
			int y=rear(lc[x]);
			splay(y,x);
			rc[y]=rc[x];
			if(rc[x]) fa[rc[x]]=y;
			update(y);root=y;fa[y]=0;
			lc[x]=rc[x]=fa[x]=0;
			sz[x]=1;
			push_front(root,x);
			splay(x,0);
			return;
		}
		void bottom(int x){
			splay(x,0);
			if(!rc[x]) return;
			int y=front(rc[x]);
			splay(y,x);
			lc[y]=lc[x];
			if(lc[x]) fa[lc[x]]=y;
			update(y);root=y;fa[y]=0;
			lc[x]=rc[x]=fa[x]=0;
			sz[x]=1;
			push_rear(root,x);
			splay(x,0);
			return;
		}
		void insert(int x,int k){
			int y;
			if(!k) return;
			splay(x,0);
			if(k==1) y=front(rc[x]);
			else y=rear(lc[x]);
			splay(y,x);
			exchange(x,y);
			root=y;
			return;
		}
		int ask(int x){
			splay(x,0);
			return sz[lc[x]];
		}
		int query(int x){
			return get_id(root,x);
		}
} T;
int main(){
	int i,s,x;
	char op[10];
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
		scanf("%d",&a[i]);
	T.build();
	for(i=1;i<=m;++i){
		scanf("%s",op);
		if(op[0]=='T'){
			scanf("%d",&s);
			T.top(s);
		}
		else if(op[0]=='B'){
			scanf("%d",&s);
			T.bottom(s);
		}
		else if(op[0]=='I'){
			scanf("%d%d",&s,&x);
			T.insert(s,x);
		}
		else if(op[0]=='A'){
			scanf("%d",&s);
			printf("%d\n",T.ask(s));
		}
		else{
			scanf("%d",&s);
			printf("%d\n",T.query(s));
		}
	}
	// system("pause");
	return 0;
}
上一篇:[翻译] Visual Studio 2019 RC版发布


下一篇:【DB宝49】Oracle如何设置DB、监听和EM开机启动