洛谷p2596[zjoi2006]书架splay(代码片段)

niiick niiick     2022-10-31     587

关键词:

题目描述

小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。

小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。

当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。

久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。

输入格式:

第一行有两个数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本书的编号。

输出格式:

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

输入样例

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

输出样例

2
9
9
7
5
3

说明

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

题目分析:

Top
把指定元素编号旋转到根
1.若此时根节点无左子树,则直接返回

2.若此时根节点无右子树,则直接交换左右子树

3.左右子树均存在
找到当前序列中排名为size[ch[rt][0]+2的编号,设为y
(即找到当前根节点元素在序列中的的下一个元素编号,后继)
令根的左子树成为y的左子树(ch[y][0]=ch[rt][0])

Bottom
把指定元素编号旋转到根
1.若此时根节点无右子树,则直接返回

2.若此时根节点无左子树,则直接交换左右子树

3.左右子树均存在
找到当前序列中排名为size[ch[rt][0]的编号,设为y
(即找到当前根节点元素在序列中的的上一个元素编号,前驱)
令根的右子树成为y的右子树(ch[y][1]=ch[rt][1])

Insert
t=0时直接忽略操作
把指定元素编号旋转到根
若t=1,找到根节点后继,交换编号及元素信息
若t=-1,找到根节点前驱,交换编号及元素信息

Ask
把指定元素编号旋转到根
输出根节点左子树大小

Query
常规find操作
****************************************

#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()

    int f=1,x=0;
    char ss=getchar();
    while(ss<‘0‘||ss>‘9‘)if(ss==‘-‘)f=-1;ss=getchar();
    while(ss>=‘0‘&&ss<=‘9‘)x=x*10+ss-‘0‘;ss=getchar();
    return f*x;


void print(int x)

    if(x<0)putchar(‘-‘);x=-x;
    if(x>9)print(x/10);
    putchar(x%10+‘0‘);


int n,m,rt;
int v[100010],pos[100010],size[100010];
int ch[100010][2],fa[100010],sz;
char ss[20];

void update(int p)

    size[p]=size[ch[p][0]]+size[ch[p][1]]+1;


void rotate(int& p,int x)  
    int y=fa[x],z=fa[y]; 
    int t=(ch[y][0]==x);
    if(y==p) p=x; 
    else if(ch[z][0]==y) ch[z][0]=x; 
    else ch[z][1]=x;  
    fa[y]=x; fa[ch[x][t]]=y; fa[x]=z;  
    ch[y][t^1]=ch[x][t]; ch[x][t]=y;   
    update(y);update(x);  
 

void splay(int& p,int x) 
   
    while(x!=p) 
    
        int y=fa[x],z=fa[y];
        if(y!=p) 
        
            if((ch[y][0]==x)^(ch[z][0]==y)) rotate(p,x);
            else rotate(p,y);
        
        rotate(p,x);
    


void ins(int x)

    v[++sz]=x; pos[x]=sz;
    size[sz]=1; ch[sz][0]=ch[sz][1]=0;
    if (sz>1)
    
        ch[sz-1][1]=sz;fa[sz]=sz-1;
        splay(rt,sz);
    


int find(int p,int k)

    int ss=size[ch[p][0]];
    if(ss+1==k) return p;
    else if(ss>=k) return find(ch[p][0],k);
    else return find(ch[p][1],k-ss-1); 


void top_bottom(int d)

    int x=read(),y; x=pos[x];
    splay(rt,x);//指定元素旋转到根
    if(!ch[x][d]) return;//第1种情况
    if(!ch[x][d^1]) ch[x][d^1]=ch[x][d]; ch[x][d]=0; return;//第2种情况
    
    if(d==0) y=find(rt,size[ch[x][0]]+2);//元素置顶,找到根的后继
    else y=find(rt,size[ch[x][0]]);//元素置底,找到根的前驱
    fa[ch[rt][d]]=y;//合并子树
    ch[y][d]=ch[rt][d];
    ch[rt][d]=0;
    splay(rt,y);//伸展保证复杂度


void change()

    int x=read(),d=read(),y; if(d==0) return;//d=0直接忽略
    splay(rt,pos[x]);//指定元素旋转到根
    if(d==1) y=find(rt,size[ch[pos[x]][0]]+2);//元素提前,找到其前驱
    else y=find(rt,size[ch[pos[x]][0]]);//元素置后,找到其后继
    int tv=v[y],tpos=pos[x];//交换信息
    swap(pos[x],pos[tv]);
    swap(v[tpos],v[y]);


int get()

    int x=read(); x=pos[x];
    splay(rt,x);
    return size[ch[x][0]];


int main()

    n=read();m=read();rt=1;
    for(int i=1;i<=n;++i)
    
        int x=read();ins(x);
    
    
    while(m--)
    
        scanf("%s",&ss);
        if(ss[0]==‘T‘) top_bottom(0);
        else if(ss[0]==‘B‘) top_bottom(1);
        else if(ss[0]==‘I‘) change();
        else if(ss[0]==‘A‘) print( get() ),putchar(‘\n‘);
        else if(ss[0]==‘Q‘) print( v[ find(rt,read()) ] ),putchar(‘\n‘);
    
    
    return 0;

题解[zjoi2006]书架(splay)

懒得复制,戳我戳我Solution:还是一个\(Splay\),我们只用多存一个值\(rad\)来维护二叉树,然后用数组存下每个书对应的值是多少\(Top\)操作,我是把\(s\)旋转到根节点,然后删除,将\(s\)对应的\(rad\)值调至最小,然后插入就可以\(Bot... 查看详情

bzoj1861:[zjoi2006]book书架(splay)

1861:[Zjoi2006]Book书架TimeLimit: 4Sec  MemoryLimit: 64MBSubmit: 1453  Solved: 822[Submit][Status][Discuss]Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到 查看详情

bzoj1861[zjoi2006]book书架——splay

【题目分析】  模板题目。  首尾两个虚拟结点,十分方便操作。【代码】#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<map>#include<set>#include<queue& 查看详情

bzoj1861:[zjoi2006]book书架splay

1861:[Zjoi2006]Book书架Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。... 查看详情

1861.[zjoi2006]书架平衡树-splay(代码片段)

Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引... 查看详情

zjoi2006书架(代码片段)

传送门这道题与普通的(splay)不大相同,别的都是以权值来排序,但这道题是以位置进行排序的,也就是对于一个节点,它的左子树中的节点都在它的上面,右子树中的节点都在他的下面。这个比较独特的一点在于建树,这次不... 查看详情

[zjoi2006]书架(权值splay)(代码片段)

[ZJOI2006]书架(luogu)Description题目描述小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿... 查看详情

bzoj1861:[zjoi2006]书架——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=1861(题面复制于洛谷)题目描述小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一... 查看详情

[题解]bzoj1861book书架-splay

1861:[Zjoi2006]Book书架TimeLimit: 4Sec  MemoryLimit: 64MBSubmit: 1396  Solved: 803[Submit][Status][Discuss]Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到 查看详情

[zjoi2006]book书架

pre.cjk{font-family:"DroidSansFallback",monospace}p{margin-bottom:0.25cm;line-height:120%}a:link{}1861:[Zjoi2006]Book书架TimeLimit:4Sec  MemoryLimit:64MBSubmit:1581  Solved:884[Submi 查看详情

[zjoi2006]书架(代码片段)

[题目链接]     https://www.lydsy.com/JudgeOnline/problem.php?id=1861[算法]    平衡树    时间复杂度:O(MlogN)[代码]      &n 查看详情

[luogu2596]zjoi2006书架

[Luogu2596]ZJOI2006书架<题目链接>第一次指针写FHQ_Treap(省选噩梦数据结构)AC啦!省选试机写它,紧张过度失败了。省选Day1考场写它,写挂了。省选Day1当晚认真复习它,结果Day2并不考。于是省选后用指针写出来了,开心qwq。... 查看详情

[zjoi2006]书架(代码片段)

[ZJOI2006]书架题目描述小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这... 查看详情

解题:zjoi2006书架(代码片段)

题面学习了如何在维护序列的平衡树上查找某个数:按初始的顺序定个权值,然后每次找那个权值的DFS序即可。具体实现就是不停往上跳,然后是父亲的右儿子就加上父亲的左儿子,剩下的就是继续熟悉无旋树堆1#include<cstdio&g... 查看详情

bzoj1861:[zjoi2006]book书架

BZOJ1861:[Zjoi2006]Book书架Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本... 查看详情

[bzoj1861][zjoi2006]book书架

[BZOJ1861][Zjoi2006]Book书架试题描述小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一... 查看详情

bzoj1861[zjoi2006]book书架

1#include<bits/stdc++.h>2usingnamespacestd;3constintN=8e4+5;4constintinf=1e9;5intfa[N],c[N][2],size[N],pos[N],a[N],v[N],n,m,rt;6voidupdate(intx)7{8size[x]=size[c[x][0]]+size[c[x][1]]+1;9}10voidr 查看详情

「luogu2596」[zjoi2006]书架(代码片段)

用平衡树维护每本书的位置1#include<bits/stdc++.h>2usingnamespacestd;3constintN=80010;4intn,m,maxpos,minpos,book[N<<2],bookpos[N];5introot,fa[N<<2],ch[N<<2][2],siz[N<<2],pos[N<<2 查看详情