zoukankan      html  css  js  c++  java
  • BZOJ1861: [Zjoi2006]Book 书架

    BZOJ1861: [Zjoi2006]Book 书架

    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

    题解Here!
    Splay比较好做,那就一发 Splay 吧。
    1. Top 和 Bottom 实质上就是把序列中的一个数放到第一个和最后一个。
    具体实现可以把要操作的节点提到根节点,然后把左子树合并到右子树上或把右子树合并到左子树上。

    2. Insert操作就是把要操作的节点和前驱后继交换位置,即:把两个点的特征值即编号进行交换。

    3. Ask操作询问序列中在此节点前面的数有多少个,提到根节点输出左儿子size就可以了。

    4. Query操作就是一个简单的查询序列中第s个数的编号,相当于查询第k大,kth即可。

    由于我们需要定位编号为s的节点在树中的位置,所以我使用了 id 数组记录并维护。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 80010
    using namespace std;
    int n,m,root=1,c=1,id[MAXN];
    struct node{
    	int son[2];
    	int f,v,s;
    }a[MAXN];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline void clean(int rt){
    	a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].v=a[rt].s=0;
    }
    inline void pushup(int rt){
    	if(!rt)return;
    	a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
    	id[a[a[rt].son[0]].v]=a[rt].son[0];id[a[a[rt].son[1]].v]=a[rt].son[1];
    }
    inline void turn(int rt,int k){
    	int x=a[rt].f,y=a[x].f;
    	a[x].son[k^1]=a[rt].son[k];
    	if(a[rt].son[k])a[a[rt].son[k]].f=x;
    	a[rt].f=y;
    	if(y)a[y].son[a[y].son[1]==x]=rt;
    	a[x].f=rt;
    	a[rt].son[k]=x;
    	pushup(x);pushup(rt);
    }
    void splay(int rt,int ancestry){
    	while(a[rt].f!=ancestry){
    		int x=a[rt].f,y=a[x].f;
    		if(y==ancestry)turn(rt,a[x].son[0]==rt);
    		else{
    			int k=a[y].son[0]==x?1:0;
    			if(a[x].son[k]==rt){turn(rt,k^1);turn(rt,k);}
    			else{turn(x,k);turn(rt,k);}
    		}
    	}
    	if(ancestry==0)root=rt;
    }
    int kth(int rt,int x){
    	int y=a[rt].son[0];
    	if(a[y].s+1==x)return rt;
    	else if(x<=a[y].s)return kth(y,x);
    	else return kth(a[rt].son[1],x-a[y].s-1);
    }
    inline void newnode(int x){
    	int rt=c++;
    	a[rt].son[0]=a[rt].son[1]=0;
    	a[rt].v=x;a[rt].s=1;id[x]=rt;
    	if(rt==1)return;
    	a[rt-1].son[1]=rt;a[rt].f=rt-1;
    	splay(rt,0);
    }
    inline void top(int x){
    	int rt=id[x];
    	splay(rt,0);
    	if(!a[rt].son[0])return;
    	if(!a[rt].son[1]){
    		a[rt].son[1]=a[rt].son[0];
    		a[rt].son[0]=0;
    	}
    	else{
    		int y=kth(root,a[a[rt].son[0]].s+2);
    		a[a[root].son[0]].f=y;
    		a[y].son[0]=a[root].son[0];
    		a[root].son[0]=0;
    		splay(y,0);
    	}
    }
    inline void bottom(int x){
    	int rt=id[x];
    	splay(rt,0);
    	if(!a[rt].son[1])return;
    	if(!a[rt].son[0]){
    		a[rt].son[0]=a[rt].son[1];
    		a[rt].son[1]=0;
    	}
    	else{
    		int y=kth(root,a[a[rt].son[0]].s);
    		a[a[root].son[1]].f=y;
    		a[y].son[1]=a[root].son[1];
    		a[root].son[1]=0;
    		splay(y,0);
    	}
    }
    inline void insert(int x,int y){
    	if(!y)return;
    	splay(id[x],0);
    	int p,q,k=kth(root,a[a[id[x]].son[0]].s+y+1);
    	p=a[k].v;q=id[x];
    	swap(id[x],id[p]);swap(a[q].v,a[k].v);
    }
    inline int ask(int x){
    	x=id[x];
    	splay(x,0);
    	return a[a[x].son[0]].s;
    }
    int main(){
    	char ch[10];
    	int x,y;
    	n=read();m=read();
    	for(int i=1;i<=n;i++){
    		x=read();
    		newnode(x);
    	}
    	while(m--){
    		scanf("%s",ch);x=read();
    		switch(ch[0]){
    			case 'T':top(x);break;
    			case 'B':bottom(x);break;
    			case 'I':y=read();insert(x,y);break;
    			case 'A':printf("%d
    ",ask(x));break;
    			case 'Q':printf("%d
    ",a[kth(root,x)].v);break;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    JavaScript基础
    WordPress站点绑定多个域名
    linux下如何把php升级到5.6
    ansible shell 之运行后台程序
    Redhat7 开机启动服务
    模拟jenkins通过shell给ansible传入变量
    ansible-playbook权限提升多种方式
    ansible删除目录下所有内容
    ansible 文件和目录操作
    linux 用户和组管理
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/8977842.html
Copyright © 2011-2022 走看看