1861: [Zjoi2006]Book 书架

1861: [Zjoi2006]Book 书架

Time Limit: 4 Sec   Memory Limit: 64 MB
Submit: 1271   Solved: 731
[ Submit][ Status][ Discuss]

Description

小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。 当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。 久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。

Input

第一行有两个数n,m,分别表示书的个数以及命令的条数;第二行为n个正整数:第i个数表示初始时从上至下第i个位置放置的书的编号;第三行到m+2行,每行一条命令。命令有5种形式: 1. Top S——表示把编号为S的书房在最上面。 2. Bottom S——表示把编号为S的书房在最下面。 3. Insert S T——T∈{-1,0,1},若编号为S的书上面有X本书,则这条命令表示把这本书放回去后它的上面有X+T本书; 4. Ask S——询问编号为S的书的上面目前有多少本书。 5. Query S——询问从上面数起的第S本书的编号。

Output

对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。

Sample Input

10 10
1 3 2 7 5 8 10 4 9 6
Query 3
Top 5
Ask 6
Bottom 3
Ask 3
Top 6
Insert 4 -1
Query 5
Query 2
Ask 2

Sample Output

2
9
9
7
5
3

HINT

数据范围


100%的数据,n,m < = 80000

 

Source

[ Submit][ Status][ Discuss]

这很显然是用splay打出一片天下--
涉及单点插入删除,以及查询排名编号。。都是基本操作
本想着有点久没打splay练练手,,结果细节处理不当。。
重建父边和maintain有些地方漏打,导致WA了一次。。。额
代码能力还是要提高!!
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 8E4 + 80;

int n,m,Root,ch[maxn][2],fa[maxn],siz[maxn],a[maxn];
char com[20];

void maintain(int x)
{
	siz[x] = 1;
	for (int i = 0; i < 2; i++)
		siz[x] += siz[ch[x][i]];
}

void rotate(int x)
{
	int y = fa[x],d = ch[y][0] == x?0:1;
	ch[y][d] = ch[x][d^1];
	fa[ch[y][d]] = y; ch[x][d^1] = y;
	fa[x] = fa[y]; fa[y] = x;
	int z = fa[x]; ch[z][ch[z][1] == y] = x;
	maintain(y); maintain(x);
}

void splay(int u,int v)
{
	int g = fa[v];
	for (int y = fa[u]; y != g; rotate(u),y = fa[u])
		if (fa[y] != g)
			rotate((ch[y][0] == u)^(ch[fa[y]][0] == y)?y:u);
	if (v == Root) Root = u;
}

int Rank(int x)
{
	splay(x,Root);
	return siz[ch[x][0]] + 1;
}

int Find(int x,int k)
{
	int Left = siz[ch[x][0]] + 1;
	if (Left == k) return x;
	if (Left < k) return Find(ch[x][1],k - Left);
	return Find(ch[x][0],k);
}

void Del(int x)
{
	int rank = Rank(x);
	splay(Find(Root,rank - 1),Root);
	splay(x,ch[Root][1]);
	ch[Root][1] = ch[x][1];
	fa[ch[x][1]] = Root;
	fa[x] = ch[x][1] = 0;
	maintain(Root);
}

void Build(int l,int r,int &x)
{
	if (l > r) return;
	if (l == r) {x = a[l]; maintain(x); return;}
	int mid = (l + r) >> 1;
	x = a[mid];
	Build(l,mid - 1,ch[x][0]);
	fa[ch[x][0]] = x;
	Build(mid + 1,r,ch[x][1]);
	fa[ch[x][1]] = x;
	maintain(x);
}

int getcom()
{
	scanf("%s",com);
	if (com[0] == 'T') return 1;
	if (com[0] == 'B') return 2;
	if (com[0] == 'I') return 3;
	if (com[0] == 'A') return 4;
	return 5;
}

void Swap(int x,int y,int d)
{
	for (int i = 0; i < 2; i++) {
		fa[ch[x][i]] = y;
		fa[ch[y][i]] = x;
		swap(ch[x][i],ch[y][i]);
	} 
	fa[y] = 0; fa[x] = y; 
	Root = y; ch[y][d] = x; 
	maintain(x); maintain(y);
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n >> m; a[0] = n + 1;
	for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
	Build(0,n,Root);
	while (m--) {
		int typ = getcom();
		if (typ == 1) {
			int s; scanf("%d",&s); Del(s);
			splay(Find(Root,2),Root);
			int t = ch[Root][0];
			fa[s] = t; ch[t][1] = s;
			maintain(s); maintain(t); maintain(Root);
		}
		else if (typ == 2) {
			int s; scanf("%d",&s); Del(s);
			splay(Find(Root,n),Root);
			fa[s] = Root; ch[Root][1] = s;
			maintain(s); maintain(ch[Root][1]); maintain(Root);
 		}
		else if (typ == 3) {
			int s,t; scanf("%d%d",&s,&t);
			if (!t) continue;
			int rank = Rank(s);
			if (rank == 2 && t == -1) continue;
			if (rank == n + 1 && t == 1) continue;
			if (t == -1) {
				splay(Find(Root,rank - 1),Root);
				splay(s,ch[Root][1]); Swap(Root,s,1);
			}
			else {
				splay(Find(Root,rank + 1),Root);
				splay(s,ch[Root][0]); Swap(Root,s,0);
			}
		}
		else if (typ == 4) {
			int s; scanf("%d",&s);
			printf("%d\n",Rank(s) - 2);
			splay(s,Root);
		}
		else {
			int s; scanf("%d",&s);
			int Ans = Find(Root,s + 1);
			printf("%d\n",Ans);
			splay(Ans,Root);
		}
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值