洛谷 P3391:文艺平衡树 ← Splay树模板题

【题目来源】
https://www.luogu.com.cn/problem/P3391

【题目描述】
您需要写一种数据结构(可参考题目标题),来维护一个有序数列。  其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 1,翻转区间是 [2,4] 的话,结果是 5 2 3 4 1。

【输入格式】
第一行两个正整数 n,m,表示序列长度与操作个数。序列中第 i 项初始为 i。 接下来 m 行,每行两个正整数 l,r,表示翻转的区间。  输出格式 输出一行 n 个正整数,表示原始序列经过 m 次变换后的结果。

【输出格式】
输出一行 n 个正整数,表示原始序列经过 m 次变换后的结果。

【输入样例】
5 3
1 3
1 3
1 4

【输出样例】
​4 3 2 1 5

【数据范围】
对于 100% 的数据,1≤n,m≤100000,1≤l≤r≤n。

【算法分析】
Splay 树简介:https://blog.csdn.net/hnjzsyjyj/article/details/138504578
Treap 树解决平衡的办法是给每个结点加上一个随机的优先级,实现概率上的平衡。Splay 树直接用旋转调整树的形态,通过旋转改善树的平衡性。计算量小,效果好。
● Splay 树的旋转主要分为“
单旋”和“双旋”。
所谓“单旋”,即把结点 x 与它的父结点交换位置,使结点 x 上升一层。“单旋”不会减少树的层数,对改善平衡性没有帮助。根据旋转方向,“单旋”又分为
左旋(zag)右旋(zig)
所谓“双旋”,即两次“单旋”。“双旋”同时旋转
结点 x父结点 f 祖父结点 g 等3个结点,能改善平衡性。“双旋”又分为“一字旋”与“之字旋”。
● Splay 树的旋转示意图

Splay 树的基本操作是把结点旋转到树的根部,这样下次访问它时,只需查一次就 OK 了。
● Splay 树是
动态树(LCT,Link Cut Tree)与树链剖分的基础。
● Splay 树
曾经最常使用的 BST。不过,现在经常使用 FHQ Treap 树实现很多传统的 Splay 树的题目。因为,FHQ Treap 树代码更容易写,效率也很高,且可做持久化

【算法代码】
下面代码是 Splay 树的模板代码,但其中包含了本题(洛谷 P3391)未用的函数。例如:
本例使用了 pushup()、pushdown()、rotate()、splay()、insert()、get_val_by_pri() 、output() 等7个函数;未使用 find()、get_pre()、get_suc()、remove()、get_pri_by_val() 等5个函数。

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+5;
int n,m;
int root,idx;

struct Node {
    int s[2],v,p; //subtree,val,root
    int size,cnt;
    int lazy;
} tr[maxn];

void pushup(int x) {
    tr[x].size=tr[tr[x].s[0]].size+tr[tr[x].s[1]].size+tr[x].cnt;
}

void pushdown(int x) {
    if(tr[x].lazy) {
        swap(tr[x].s[0],tr[x].s[1]);
        tr[tr[x].s[0]].lazy^=1;
        tr[tr[x].s[1]].lazy^=1;
        tr[x].lazy=0;
    }
}

void rotate(int x) {
    int y=tr[x].p;
    int z=tr[y].p;
    int k=(tr[y].s[1]==x);

    tr[z].s[tr[z].s[1]==y]=x, tr[x].p=z;
    tr[y].s[k]=tr[x].s[k^1], tr[tr[x].s[k^1]].p=y;
    tr[x].s[k^1]=y, tr[y].p=x;

    pushup(y), pushup(x);
}

void splay(int x,int k) {
    while(tr[x].p!=k) {
        int y=tr[x].p;
        int z=tr[y].p;
        if(z!=k) {
            if((tr[y].s[0]==x)^(tr[z].s[0]==y)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
    if(!k) root=x;
}

void insert(int x) {
    int u=root, p=0;
    while(u && tr[u].v!=x) {
        p=u;
        u=tr[u].s[x>tr[u].v];
    }
    if(u) tr[u].cnt++;
    else {
        u=++idx;
        if(p) tr[p].s[x>tr[p].v]=u;
        tr[u].p=p, tr[u].v=x, tr[u].size=1;
        tr[u].cnt=1;
    }
    splay(u,0);
}

void find(int x) {
    int u=root;
    while(tr[u].s[x>tr[u].v] && tr[u].v!=x) u=tr[u].s[x>tr[u].v];
    splay(u,0);
}

int get_pre(int x) {
    find(x);
    if(tr[root].v<x) return root;
    int u=tr[root].s[0];
    while(tr[u].s[1]) u=tr[u].s[1];
    splay(u,0);
    return u;
}

int get_suc(int x) {
    find(x);
    if(tr[root].v>x) return root;
    int u=tr[root].s[1];
    while(tr[u].s[0]) u=tr[u].s[0];
    splay(u,0);
    return u;
}

void remove(int x) {
    int pre=get_pre(x), suc=get_suc(x);
    splay(pre,0), splay(suc,pre);
    int del=tr[suc].s[0];
    if(tr[del].cnt>1) tr[del].cnt--, splay(del,0);
    else tr[suc].s[0]=0, splay(suc,0);
}

int get_pri_by_val(int x) {
    insert(x);
    int ans=tr[tr[root].s[0]].size;
    remove(x);
    return ans;
}

int get_val_by_pri(int x) {
    int u=root;
    while(true) {
        pushdown(u);
        if(x<=tr[tr[u].s[0]].size) u=tr[u].s[0];
        else if(x==tr[tr[u].s[0]].size+1) return u;
        else x-=tr[tr[u].s[0]].size+1, u=tr[u].s[1];
    }
    return -1;
}

void output(int x) {
    pushdown(x);
    if(tr[x].s[0]) output(tr[x].s[0]);
    if(1<=tr[x].v && tr[x].v<=n) printf("%d ",tr[x].v);
    if(tr[x].s[1]) output(tr[x].s[1]);
}

int main() {
    scanf("%d %d",&n,&m);
    for(int i=0; i<=n+1; i++) insert(i);

    while(m--) {
        int le,ri;
        scanf("%d%d",&le,&ri);
        le=get_val_by_pri(le);
        ri=get_val_by_pri(ri+2);

        splay(le,0);
        splay(ri,le);
        tr[tr[ri].s[0]].lazy^=1;
    }

    output(root); //inorder

    return 0;
}

/*
in:
5 3
1 3
1 3
1 4

out:
4 3 2 1 5
*/




【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/138504578
https://www.acwing.com/file_system/file/content/whole/index/content/6921304/
https://www.acwing.com/file_system/file/content/whole/index/content/6420964/



 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/600427.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分布式任务调度工具 XXL-JOB

默认的账号密码是&#xff1a;admin/123456 一&#xff0c;部署docker容器 docker run \ -e PARAMS"--spring.datasource.urljdbc:mysql://192.168.150.101:3306/xxl_job?Unicodetrue&characterEncodingUTF-8 \ --spring.datasource.usernameroot \ --spring.dataso…

【刷题篇】双指针(一)

文章目录 1、移动零2、复写零3、快乐数4、盛最多水的容器 1、移动零 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 class Solution { pub…

区间预测——conformal tights

conformal tights 是一个python包 特征&#xff1a; sklearn元估计器&#xff1a;向任何scikit-learn回归器添加分位数和区间的共形预测 darts预测&#xff1a;向任何scikit-learn回归器添加共形校准的概率预测 保形校准&#xff1a;准确的分位数和可靠的覆盖的区间 相干分…

开源go实现的iot物联网新基建平台

软件介绍 Magistrala IoT平台是由Abstract Machines公司开发的创新基础设施解决方案&#xff0c;旨在帮助组织和开发者构建安全、可扩展和创新的物联网应用程序。曾经被称为Mainflux的平台&#xff0c;现在已经开源&#xff0c;并在国际物联网领域受到广泛关注。 功能描述 多协…

数据结构——链表专题3

文章目录 一、判断链表是否有环二、返回入环的第一个节点三、随机链表的复制 一、判断链表是否有环 原题链接&#xff1a;判断链表是否有环 这道题可以使用快慢指针&#xff0c;fast一次走两步&#xff0c;slow一次走一步&#xff0c;如果有环&#xff0c;它们在环里面必定会…

Java 框架安全:Spring 漏洞序列.(CVE-2022-22965)

什么叫 Spring 框架. Spring 框架是一个用于构建企业级应用程序的开源框架。它提供了一种全面的编程和配置模型&#xff0c;可以简化应用程序的开发过程。Spring 框架的核心特性包括依赖注入&#xff08;Dependency Injection&#xff09;、面向切面编程&#xff08;Aspect-Or…

TCP经典异常问题探讨与解决

作者&#xff1a;kernelxing TCP的经典异常问题无非就是丢包和连接中断&#xff0c;在这里我打算与各位聊一聊TCP的RST到底是什么&#xff1f;现网中的RST问题有哪些模样&#xff1f;我们如何去应对、解决&#xff1f;本文将从RST原理、排查手段、现网痛难点案例三个板块自上而…

【Linux系列】file命令

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

yum仓库和NFS网络共享服务

一、yum 1.1yum的定义 yum是一个基于RPM包&#xff0c;构建的软件更新机制&#xff0c;能够自动解决软件包之间的依赖关系。解决了日常工作中的大量查找安装依赖包的时间 为什么会有依赖关系的发生 因为linux本身就是以系统简洁为自身优势&#xff0c;所以在安装操作系统的时…

DB-GPT: Empowering Database Interactions with Private Large Language Models 导读

本文介绍了一种名为DB-GPT的新技术&#xff0c;它将大型语言模型&#xff08;LLM&#xff09;与传统数据库系统相结合&#xff0c;提高了用户使用数据库的体验和便利性。DB-GPT可以理解自然语言查询、提供上下文感知的回答&#xff0c;并生成高准确度的复杂SQL查询&#xff0c;…

搭建父模块和工具子模块

第一章 项目父模块搭建 1.1 nancal-idsa 作为所有工程的父工程&#xff0c;用于管理项目的所有依赖版本。 1.2 指定 pom 类型模块&#xff0c;删除 src 目录&#xff0c;点击Reload project 1.3 添加依赖 pom.xml <parent> <groupId>org.springframework.…

鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断

关于中断部分系列篇将用三篇详细说明整个过程. 中断概念篇 中断概念很多&#xff0c;比如中断控制器&#xff0c;中断源&#xff0c;中断向量&#xff0c;中断共享&#xff0c;中断处理程序等等.本篇做一次整理.先了解透概念才好理解中断过程.用海公公打比方说明白中断各个概念…

端口被其他进程占用:OSError: [Errno 98] Address already in use

一、问题描述 错误提示端口号正在被使用 二、解决办法 1.使用 lsof 命令&#xff0c;列出所有正在监听&#xff08;即被绑定&#xff09;的网络连接&#xff0c;包括它们所使用的端口号 sudo lsof -i -P -n | grep LISTEN 2.解绑被绑定的端口号 根据 netstat 或 lsof 命令…

基于OpenPCDet框架进行Pointpillars算法环境搭建并基于TensorRT和ROS部署

文章目录 参考链接1.创建虚拟环境2.安装OpenDet3.安装用于模型转换的库4.数据集转换5.模型训练6.部署安装tensorrt模型转换 编译ROS工程结果报错梳理【报错1】【报错2】【报错3】【报错4】【报错5】 参考链接 基于OpenDet进行训练&#xff0c;基于tensorrt-8.5进行部署并移植到…

常见错误以及如何纠正它们

团队和关键结果目标 (OKR) 之间的关系是深刻且至关重要的。总而言之&#xff0c;一切都应该是相互关联的。正如《团队的智慧》一书中所强调的&#xff1a; 在团队中&#xff0c;没有什么比每个成员对共同目标和一组相关绩效目标的承诺更重要的了&#xff0c;而团队对此负有共同…

经常发文章的你是否想过定时发布是咋实现的?

前言 可乐他们团队最近在做一个文章社区平台,由于人手不够,前后端都是由前端同学来写。后端使用 nest 来实现。 某一天周五下午,可乐正在快乐摸鱼,想到周末即将来临,十分开心。然而,产品突然找到了他,说道:可乐,我们要做一个文章定时发布功能。 现在我先为你解释一…

值得收藏!修复Windows 10/11中找不到输出或输入设备的五种方法

序言 这篇文章主要关注处理声音输出/输入设备未发现的问题。它提供了许多可行的方法,帮助了许多Windows用户。阅读以下内容以找到你的解决方案。 最近,我将Windows 10更新到21H2,发现我的音频无法工作。当我把鼠标放在任务栏上的声音图标(上面有一个十字图标)上时,它会…

市面上好用的AI工具有哪些?

市面上的AI工具数不胜数&#xff0c;选择合适自己的AI工具则需要考虑自己的需求&#xff0c;看是否能满足的使用需求。那么市面上又有哪些好用的AI工具呢&#xff1f; 泰迪智能科技拥有简单易用的大数据挖掘建模平台&#xff0c;能够让数据创造更大的价值。 功能板块&…

基于Springboot的校园新闻管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园新闻管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

Android 巧用putBinder方法传递大文件

使用Intent传递数据大家都知道&#xff0c;但是如果你使用Intent传递大于1Mb的数据时&#xff0c;就一定会报如下的错误&#xff1a; Caused by: android.os.TransactionTooLargeException: data parcel size 1049112 bytes 就是说你的传输数据太大了&#xff0c;当前的大小达…