news 2026/4/3 23:08:56

进阶数据结构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/4/1 15:55:25

【MCP续证冲刺必备】:Agent开发考核高频考点与避坑策略

第一章&#xff1a;MCP续证Agent开发考核概述在MCP&#xff08;Microsoft Certified Professional&#xff09;续证体系中&#xff0c;Agent开发考核是验证开发者对自动化代理系统设计与实现能力的重要环节。该考核聚焦于候选人在分布式环境下的任务调度、状态管理与通信机制等…

作者头像 李华
网站建设 2026/4/2 5:43:43

当Gemini 3.0横空出世,DeepSeek-V3.2如何用开源打破垄断?

简介 DeepSeek-V3.2以开源路线对抗国际巨头&#xff0c;通过DSA稀疏注意力机制、可扩展GRPO训练框架和大规模合成Agent数据集三大创新&#xff0c;实现性能追平Gemini 3.0 Pro但价格仅为1/5。文章介绍了其技术突破、实战表现及开源战略意义&#xff0c;承认仍有约10%差距但正在…

作者头像 李华
网站建设 2026/3/21 6:02:48

剪辑er必备!30个免费无版权音乐素材网站(2025年12月整理)

剪辑视频时&#xff0c;商用无版权的纯音乐、音效素材始终是刚需&#xff01;今天整理了国内外 30 个高性价比音频素材网站&#xff0c;涵盖免费商用、日系 BGM、特效音效等全场景&#xff0c;分类清晰、下载便捷&#xff0c;剪辑师、自媒体人直接收藏备用&#xff5e;1. 曲多多…

作者头像 李华