splay学习小结1.1【BZOJ 1861】[Zjoi2006]Book 书架

1.1

早几天以为splay是以权值为关键字的,然后做这题的时候一脸懵逼。
然后才知道这个东西也可以以位置为关键字
操作的话大体都是相同的,但是search操作可以变成直接用一个数组来使得权值和节点编号一一对应
这一题是位置为关键字的模板题,所以说操作都比较好想
TOP,BOTTLE的话就直接把节点1或节点n splay一下,然后直接插入
INSERT的话就直接把两个节点对应的权值互换一下就好了
但是有很多越界方面的细节要谨慎的处理

题目

1861: [Zjoi2006]Book 书架
Time Limit: 4 Sec Memory Limit: 64 MB
Submit: 639 Solved: 372
[Submit][Status]
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
Day2

贴代码

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;

const int maxn=100005;
int father[maxn],data[maxn],cnt[maxn],a[maxn],dui[maxn];
int son[maxn][5];
int i,j,k,l,n,m,root,t1,t2,x,y,z,tot,tmp;
char s[15];

void rotate(int x,int w){
    int y;
    y=father[x];
    cnt[y]=cnt[y]-cnt[x]+cnt[son[x][w]];
    cnt[x]=cnt[x]+cnt[y]-cnt[son[x][w]];
    father[x]=father[y];
    if (father[y]) {
        if (son[father[y]][1]==y) son[father[y]][1]=x; else son[father[y]][2]=x;
    }
    son[y][3-w]=son[x][w];
    if (son[x][w]) father[son[x][w]]=y;
    father[y]=x; son[x][w]=y;
}

void splay(int x){
    int y;
    while (father[x]) {
        y=father[x];
        if (!father[y]){
            if (x==son[y][1]) rotate(x,2); else rotate(x,1);
        } else {
            if (y==son[father[y]][1]){ 
                if (x==son[y][1]) {
                    rotate(y,2); rotate(x,2);
                }
                else {
                    rotate(x,1); rotate(x,2);
                }
            } else {
                if (x==son[y][1]) {
                    rotate(x,2); rotate(x,1);
                } else {
                    rotate(y,1); rotate(x,1);
                }
            }
        }
    }
    root=x;
}
int search(int x,int w){
    splay(dui[w]);
    return dui[w];
}

int kth(int x,int w){
    int i;
    i=root;
    while ((x!=cnt[son[i][w]]+1) && (i)) {
        if (x<cnt[son[i][w]]+1){
            i=son[i][w];
        } else {
            x=x-cnt[son[i][w]]-1;
            i=son[i][3-w];
        }
    }
    splay(i);
    return root;
}

int findnum(int x,int w){
    int tmp;
    tmp=search(root,x);
    return cnt[son[root][w]];
}

void del(int x){
    int y,k;
    k=search(root,x);
    y=son[k][1];
    if (son[k][1]==0){
        y=son[k][2]; son[k][2]=0; data[k]=0; cnt[k]=0; father[y]=0; root=y;
    }
    father[y]=0;
    while (son[y][2]) y=son[y][2];
    if (y==0) y=son[k][2];
    splay(y);
    son[root][2]=son[k][2];
    cnt[root]=cnt[root]+cnt[son[k][2]];
    if (son[root][2]) father[son[root][2]]=root;
    son[k][1]=0; son[k][2]=0; cnt[k]=0; data[k]=0;
}
int main(){
    //freopen("1861.in","r",stdin);
    //freopen("1861.out","w",stdout);
    root=0;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++){
        scanf("%d",&a[i]);
        father[i]=i-1;
        if (i!=1) son[i-1][2]=i;
        data[i]=a[i]; cnt[i]=n-i+1;
        dui[a[i]]=i;
    }
    root=1;
    for (i=1;i<=m;i++){
        scanf("%s",&s);
        scanf("%d",&t1);
        if (s[0]=='Q'){
            printf("%d\n",data[kth(t1,1)]);
        } else
        if (s[0]=='A'){
            printf("%d\n",findnum(t1,1));
        } else
        if (s[0]=='T'){
            del(t1);
            t2=kth(1,1);
            tot=dui[t1]; data[tot]=t1; cnt[tot]=1; father[tot]=t2; son[t2][1]=tot; cnt[t2]++; 
        } else
        if (s[0]=='B'){
            del(t1);
            t2=kth(1,2);
            tot=dui[t1]; data[tot]=t1; cnt[tot]=1; father[tot]=t2; son[t2][2]=tot; cnt[t2]++; 
        } else {
            scanf("%d",&z);
            if (z==0) continue;
            if (z==-1) {
                x=search(root,t1);
                y=son[root][1];
                while (son[y][2]) y=son[y][2];
            } else
            if (z==1) {
                x=search(root,t1);
                y=son[root][2];
                while (son[y][1]) y=son[y][1];
            }
            if (y==0) continue;
            t1=dui[data[x]]; dui[data[x]]=dui[data[y]]; dui[data[y]]=t1;
            t1=data[x]; data[x]=data[y]; data[y]=t1;
        }
    }
    return 0;
}
内容概要:本文深入探讨了Kotlin语言在函数式编程和跨平台开发方面的特性和优势,结合详细的代码案例,展示了Kotlin的核心技巧和应用场景。文章首先介绍了高阶函数和Lambda表达式的使用,解释了它们如何简化集合操作和回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建和平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发和Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程和跨平台开发领域不断完善和发展。; 适合人群:对函数式编程和跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者和中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数和Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解和实践Kotlin的函数式编程特性和跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解和掌握。
内容概要:本文深入探讨了利用历史速度命令(HVC)增强仿射编队机动控制性能的方法。论文提出了HVC在仿射编队控制中的潜在价值,通过全面评估HVC对系统的影响,提出了易于测试的稳定性条件,并给出了延迟参数与跟踪误差关系的显式不等式。研究为两轮差动机器人(TWDRs)群提供了系统的协调编队机动控制方案,并通过9台TWDRs的仿真和实验验证了稳定性和综合性能改进。此外,文中还提供了详细的Python代码实现,涵盖仿射编队控制类、HVC增强、稳定性条件检查以及仿真实验。代码不仅实现了论文的核心思想,还扩展了邻居历史信息利用、动态拓扑优化和自适应控制等性能提升策略,更全面地反映了群体智能协作和性能优化思想。 适用人群:具备一定编程基础,对群体智能、机器人编队控制、时滞系统稳定性分析感兴趣的科研人员和工程师。 使用场景及目标:①理解HVC在仿射编队控制中的应用及其对系统性能的提升;②掌握仿射编队控制的具体实现方法,包括控制器设计、稳定性分析和仿真实验;③学习如何通过引入历史信息(如HVC)来优化群体智能系统的性能;④探索中性型时滞系统的稳定性条件及其在实际系统中的应用。 其他说明:此资源不仅提供了理论分析,还包括完整的Python代码实现,帮助读者从理论到实践全面掌握仿射编队控制技术。代码结构清晰,涵盖了从初始化配置、控制律设计到性能评估的各个环节,并提供了丰富的可视化工具,便于理解和分析系统性能。通过阅读和实践,读者可以深入了解HVC增强仿射编队控制的工作原理及其实际应用效果。
可持久化splay是一种数据结构,它是对splay树进行修改和查询的一种扩展。在传统的splay树中,对树的修改操作会破坏原有的树结构,而可持久化splay树则允许我们对树进行修改、查询,并且可以保存修改后的每个版本的树结构。 在可持久化splay树中,我们不会直接对原树进行修改,而是通过复制每个节点来创建新的版本。这样,每个版本都可以独立地修改和查询,保留了原有版本的结构和状态。每个节点保存了其左子树和右子树的引用,使得可以在不破坏原有版本的情况下进行修改和查询。 为了实现可持久化splay树,我们可以使用一些技巧,比如引用中提到的哨兵节点和假的父节点和孩子节点。这些技巧可以帮助我们处理根节点的旋转和其他操作。 此外,可持久化splay树还可以与其他数据结构相结合,比如引用中提到的可持久化线段树。这种结合可以帮助我们解决更复杂的问题,比如区间修改和区间查询等。 对于可持久化splay树的学习过程,可以按照以下步骤进行: 1. 理解splay树的基本原理和操作,包括旋转、插入、删除和查找等。 2. 学习如何构建可持久化splay树,包括复制节点、更新版本和保存历史版本等。 3. 掌握可持久化splay树的常见应用场景,比如区间修改和区间查询等。 4. 深入了解与可持久化splay树相关的其他数据结构和算法,比如可持久化线段树等。 在解决问题时,可以使用二分法来确定答案,一般称为二分答案。通过对答案进行二分,然后对每个答案进行检查,以确定最终的结果。这种方法可以应用于很多问题,比如引用中提到的在线询问问题。 综上所述,可持久化splay是一种对splay树进行修改和查询的扩展,可以通过复制节点来创建新的版本,并且可以与其他数据结构相结合解决更复杂的问题。学习过程中可以按照一定的步骤进行,并且可以使用二分法来解决一些特定的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [[学习笔记]FHQ-Treap及其可持久化](https://blog.csdn.net/weixin_34283445/article/details/93207491)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [可持久化数据结构学习笔记](https://blog.csdn.net/weixin_30376083/article/details/99902410)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值