news 2026/5/19 8:47:47

进阶数据结构Splay应用-维护数列

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
进阶数据结构Splay应用-维护数列

引言

该问题几乎包含了所有的s p l a y splaysplay操作, 如果不了解s p l a y splaysplay可以单击这里

题目-维护数列

问题分析

因为涉及到区间翻转操作, 线段树无法实现(线段树解决的是区间属性问题)

其实最复杂的操作是求区间的最大
子段和
, 可以考虑s p l a y splaysplay维护的节点信息

s p l a y splaysplay每个节点表示一个数字, 多个点构成的的中序遍历就是希望求的序列, 因此中序遍历维护的是序列

算法步骤

s p l a y splaysplay维护的节点信息

实现细节

如果一个点有延迟标记, 这个点的权值存储的是执行延迟标记之前的值还是执行延迟标记之后的值需要自己去定义

因为执行s a m e samesame或者r e v revrev延迟标记, 会对当前节点的值(m a x v , l m , r m , s u m maxv, lm, rm, summaxv,lm,rm,sum)产生影响, 可以定义当前节点的值(m a x v , l m , r m , s u m maxv, lm, rm, summaxv,lm,rm,sum)是延迟标记操作之后的值

具体的来说

对于当前节点, 如果打上了延迟标记, 那么将该节点的m a x v , l m , r m , s u m maxv, lm, rm, summaxv,lm,rm,sum都计算一遍


并且在节点执行push down延迟操作的时候, 不仅仅是直接将子节点打上标记, 而且将子节点的m a x v , l m , r m , s u m maxv, lm, rm, summaxv,lm,rm,sum计算一遍

在删除过程中需要进行内存回收优化内存, 也就是将删除的节点回收到节点池

因此初始化的时候,ms = sum = v, 不能是max(v, 0)

代码实现

注意事项:

#include<bits/stdc++.h>usingnamespacestd;constintN=5e5+10,INF=1e9;intn,m;structNode{ints[2],p,v;intrev,same,cnt;intms,ls,rs,sum;// 因为内存回收机制的存在, 必须在此刻重置rev和same的延迟标记voidinit(int_v,int_p){s[0]=s[1]=0;p=_p,v=_v;cnt=1;rev=same=0;sum=ms=v;ls=rs=max(v,0);}}tr[N];// nodes作为节点池, ptr分配节点introot,nodes[N],ptr;intw[N];voidpushup(intu){Node&lson=tr[tr[u].s[0]],&rson=tr[tr[u].s[1]];tr[u].cnt=lson.cnt+rson.cnt+1;tr[u].sum=lson.sum+rson.sum+tr[u].v;tr[u].ls=max(lson.ls,lson.sum+tr[u].v+rson.ls);tr[u].rs=max(rson.rs,rson.sum+tr[u].v+lson.rs);// 注意需要加当前节点的值tr[u].ms=max({lson.ms,rson.ms,lson.rs+tr[u].v+rson.ls});}voidpushdown(intu){Node&lson=tr[tr[u].s[0]],&rson=tr[tr[u].s[1]];if(tr[u].same){tr[u].same=tr[u].rev=0;if(tr[u].s[0]){lson.same=1;lson.v=tr[u].v;lson.sum=tr[u].v*lson.cnt;if(tr[u].v>0)lson.ms=lson.ls=lson.rs=lson.sum;else{lson.ms=tr[u].v;lson.ls=lson.rs=0;}}if(tr[u].s[1]){rson.same=1;rson.v=tr[u].v;rson.sum=tr[u].v*rson.cnt;if(tr[u].v>0)rson.ms=rson.ls=rson.rs=rson.sum;else{rson.ms=tr[u].v;rson.ls=rson.rs=0;}}}// 当子树的根被打上标记, 约定翻转, 这里就不需要翻转elseif(tr[u].rev){tr[u].rev=0;lson.rev^=1,rson.rev^=1;swap(lson.ls,lson.rs),swap(rson.ls,rson.rs);swap(lson.s[0],lson.s[1]),swap(rson.s[0],rson.s[1]);}}voidrotate(intx){inty=tr[x].p,z=tr[y].p;intk=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);}voidsplay(intx,intk){while(tr[x].p!=k){inty=tr[x].p,z=tr[y].p;if(z!=k){if((tr[z].s[1]==y)^(tr[y].s[1]==x))rotate(x);elserotate(y);}rotate(x);}if(!k)root=x;}// 将一段序列构建二叉树intbuild(intl,intr,intp){intmid=l+r>>1;intu=nodes[ptr--];tr[u].init(w[mid],p);if(l<mid)tr[u].s[0]=build(l,mid-1,u);if(r>mid)tr[u].s[1]=build(mid+1,r,u);pushup(u);returnu;}intget_k(intk){intu=root;while(u){pushdown(u);intcnt=tr[tr[u].s[0]].cnt+1;if(cnt>k)u=tr[u].s[0];elseif(cnt==k)returnu;elseu=tr[u].s[1],k-=cnt;}return0;}// 内存回收voidrelease(intu){if(tr[u].s[0])release(tr[u].s[0]);if(tr[u].s[1])release(tr[u].s[1]);nodes[++ptr]=u;}intmain(){ios::sync_with_stdio(false);cin.tie(0);// 所有点是可用的for(inti=1;i<N;++i)nodes[++ptr]=i;cin>>n>>m;for(inti=1;i<=n;++i)cin>>w[i];// 为了保证数列时刻都有数字以及如果当前节点没有左右儿子节点不会造成影响tr[0].ms=w[0]=w[n+1]=-INF;// 原序列初始化为树root=build(0,n+1,0);string op;while(m--){cin>>op;if(op=="INSERT"){intposi,tot;cin>>posi>>tot;intu=get_k(posi+1),v=get_k(posi+2);splay(u,0),splay(v,u);for(inti=0;i<tot;++i)cin>>w[i];tr[v].s[0]=build(0,tot-1,v);pushup(v),pushup(u);}elseif(op=="DELETE"){intposi,tot;cin>>posi>>tot;intu=get_k(posi),v=get_k(tot+posi+1);splay(u,0),splay(v,u);release(tr[v].s[0]);tr[v].s[0]=0;pushup(v),pushup(u);}elseif(op=="MAKE-SAME"){intposi,tot,c;cin>>posi>>tot>>c;intu=get_k(posi),v=get_k(tot+posi+1);splay(u,0),splay(v,u);Node&son=tr[tr[v].s[0]];son.same=1;son.v=c;son.sum=son.cnt*c;if(c>0)son.ms=son.ls=son.rs=son.sum;else{son.ms=c;son.ls=son.rs=0;}pushup(v),pushup(u);}elseif(op=="REVERSE"){intposi,tot;cin>>posi>>tot;intu=get_k(posi),v=get_k(tot+posi+1);splay(u,0),splay(v,u);Node&son=tr[tr[v].s[0]];son.rev^=1;swap(son.ls,son.rs);swap(son.s[0],son.s[1]);pushup(v),pushup(u);}elseif(op=="GET-SUM"){intposi,tot;cin>>posi>>tot;intu=get_k(posi),v=get_k(tot+posi+1);splay(u,0),splay(v,u);cout<<tr[tr[v].s[0]].sum<<'\n';pushup(v),pushup(u);}else{cout<<tr[root].ms<<'\n';}}return0;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 16:21:10

C语言一维数组完全指南:从基础到实战应用

掌握数组的核心概念&#xff0c;避免常见陷阱&#xff0c;提升编程效率在C语言编程中&#xff0c;数组是一种非常重要的数据结构&#xff0c;而一维数组是最基础且最常用的形式。它将相同类型的变量组织在一起&#xff0c;使得我们可以高效地处理和操作大量相关数据。本文将全面…

作者头像 李华
网站建设 2026/5/11 11:23:27

网上有不少这样的错误的数学文章危害极大

网上有不少这样的错误的数学文章危害极大黄小宁微积分最起码常识&#xff1a;自变量x的任意增量就是dx&#xff0c;dx可以取任何实数&#xff0c;因其是x的任意改变量。当x由1变为9时改变量dx就是1与9的差&#xff1b;这里x1变为xdx9&#xff0c;dx9-18。然而图片中的文章却胡说…

作者头像 李华
网站建设 2026/5/17 1:56:19

D435i Intel RealSense 安装教程

本人环境&#xff1a;Ubuntu 20.04 1. 添加 RealSense 仓库 GPG 公钥&#xff0c;并为仓库添加源&#xff1a; sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-key C8B3A55A6F3EFCDE sudo add-apt-repository "deb https://librealsense.intel.com/Debian/a…

作者头像 李华
网站建设 2026/5/11 10:52:46

医院病历管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】

摘要 随着信息技术的快速发展&#xff0c;传统纸质病历管理方式已无法满足现代医院高效、精准的管理需求。纸质病历易丢失、难检索、共享性差等问题日益突出&#xff0c;严重影响了医疗服务的质量和效率。电子病历管理系统通过数字化手段实现了病历信息的集中存储、快速检索和跨…

作者头像 李华