news 2026/5/1 8:23:23

进阶数据结构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/1 7:08:56

用AI生成随机乱码的5种高级技巧

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个可以生成随机乱码的Web应用&#xff0c;要求&#xff1a;1.支持自定义字符集&#xff08;如仅字母、数字、符号或混合&#xff09;2.可设置生成长度范围 3.能控制特殊符号出…

作者头像 李华
网站建设 2026/5/1 7:57:25

中山SEO:AI时代的“人机协作”新模式

随着AI技术的飞速发展&#xff0c;中山SEO行业正面临着巨大的变革。AI不仅能够提升工作效率&#xff0c;还能够通过智能化的数据分析和内容生成&#xff0c;帮助企业提升在搜索引擎中的排名。然而&#xff0c;AI并非万能&#xff0c;仍然存在无法替代人工干预的局限性&#xff…

作者头像 李华
网站建设 2026/4/29 18:54:43

云数据查询终极指南:5分钟构建多云资产清单

想要快速掌握云数据查询的核心技能&#xff1f;CloudQuery作为基于GraphQL的数据查询引擎&#xff0c;能够将SQL查询转换为GraphQL查询&#xff0c;帮助您轻松构建完整的云资产清单。无论您是新手还是经验丰富的云工程师&#xff0c;这个开源项目都能为您的多云环境管理带来革命…

作者头像 李华
网站建设 2026/5/1 7:57:31

ZCC1004E-120V 3A 零功耗使能异步降压电源芯片

**概述ZCC1004E是一款支持宽电压输入的开关降压型 DC-DC 控制器&#xff0c;最高输入电压 120V。具有低待机功耗、高效率、低纹波、优异的母线电压调整率和负载调整率等特性。内置150V 60mΩ功率管支持3A电流输出 可通过设置 FB 引脚的分压电阻可设置输出恒压值。 采用固定频率…

作者头像 李华