HYSBZ 1500 维修数列(伸展树模板)
题意:
题解:典型伸展树的题,比较全面。
我理解的伸展树:
1 伸展操作:就是旋转,因为我们只需保证二叉树中序遍历的结果不变,所以我们可以旋转来保持树的平衡,且旋转有左旋与右旋。通过这种方式保证不会让树一直退化从而超时。虽然一次旋转的代价比较高,但是可以证明:每次操作都旋转(关键),则时间复杂度为O(n*log2 n)
2 更新:每个节点都可以存一些信息,并模拟线段树进行区间操作。父节点的信息是两个孩子节点加当前父节点的信息的总和。因为是可旋转的搜索二叉树,所以每次处理都需要注意上更新或下更新
3 注意:一般需要先开两个哨兵节点,一个作为开头,有个作为结尾,这样可以避免一些边界的讨论问题
- #include<queue>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- #define dir(a,b) (a>>b)
- #define ssplay(rt,x) (splay[rt].chd[x])
- typedef long long ll;
- const int Max=6e5+;
- const int Inf=<<;
- int num[Max],memp[Max],tot2,tot,root;//存值 内存池 内存池的值 总值 根节点
- struct node
- {
- int file,sam;//翻转 是否修改
- int chd[],fat;
- int sizee,sum,val;//总个数 总大小 值
- int lmax,rmax,mmax;//区间合并三变量
- } splay[Max];
- void Treaval(int rt)
- {
- if(rt)
- {
- Treaval(splay[rt].chd[]);
- printf("rt=%2d lchd=%2d rchd=%2d sum=%2d size=%2d val=%2d lmax=%2d rmax=%2d mmax=%2d\n",rt,splay[rt].chd[],splay[rt].chd[],
- splay[rt].sum,splay[rt].sizee,splay[rt].val,splay[rt].lmax,splay[rt].rmax,splay[rt].mmax);
- Treaval(splay[rt].chd[]);
- }
- return;
- }
- void debug()
- {
- printf("root=%d\n",root);
- Treaval(root);
- return;
- }
- inline void NewNode(int &rt,int fa,int va)//建立新节点
- {
- if(tot2)//删除后的内存池可以再次利用
- rt=memp[tot2--];
- else
- rt=++tot;
- splay[rt].file=splay[rt].sam=;
- splay[rt].chd[]=splay[rt].chd[]=;
- splay[rt].val=splay[rt].lmax=splay[rt].rmax=splay[rt].mmax=splay[rt].sum=va;
- splay[rt].fat=fa;
- return;
- }
- inline int nmax(int a,int b)
- {
- return a>b?a:b;
- }
- inline void PushUp(int rt)//上更新(类似区间合并)
- {
- int lchd=splay[rt].chd[],rchd=splay[rt].chd[];
- splay[rt].sizee=splay[lchd].sizee+splay[rchd].sizee+;
- splay[rt].sum=splay[lchd].sum+splay[rchd].sum+splay[rt].val;
- splay[rt].mmax=nmax(nmax(splay[rt].val,splay[lchd].mmax),splay[rchd].mmax);//处理区间最大值
- if(splay[rt].mmax>)
- splay[rt].mmax=nmax(splay[rt].mmax,nmax(splay[lchd].rmax,)+nmax(splay[rchd].lmax,)+splay[rt].val);//val为关键
- splay[rt].lmax=nmax(splay[lchd].lmax,splay[lchd].sum+splay[rt].val);
- splay[rt].lmax=nmax(splay[rt].lmax,splay[lchd].sum+splay[rt].val+splay[rchd].lmax);
- splay[rt].rmax=nmax(splay[rchd].rmax,splay[rchd].sum+splay[rt].val);
- splay[rt].rmax=nmax(splay[rt].rmax,splay[rchd].sum+splay[rt].val+splay[lchd].rmax);
- return;
- }
- inline void Swap(int &a,int &b)
- {
- int t=a;
- a=b;
- b=t;
- return;
- }
- inline void fson(int rt)//翻转
- {
- if(!rt)
- return;
- Swap(splay[rt].chd[],splay[rt].chd[]);//孩子交换就好
- Swap(splay[rt].lmax,splay[rt].rmax);//此位置的左右max需交换
- splay[rt].file^=;//此处修改与否只与父节点flie有关,与此处的file无关
- }
- inline void sson(int rt,int va)//修改成va
- {
- if(!rt)
- return;
- splay[rt].val=va;
- splay[rt].sum=va*splay[rt].sizee;
- splay[rt].lmax=splay[rt].rmax=splay[rt].mmax=nmax(splay[rt].sum,va);
- splay[rt].sam=;
- }
- inline void PushDown(int rt)//下更新(处理翻转与改变值)
- {
- if(splay[rt].file)
- {
- fson(splay[rt].chd[]);
- fson(splay[rt].chd[]);
- splay[rt].file=;
- }
- if(splay[rt].sam)
- {
- sson(splay[rt].chd[],splay[rt].val);
- sson(splay[rt].chd[],splay[rt].val);
- splay[rt].sam=;
- }
- return;
- }
- inline void Rotate(int rt,int kind)//**zig或者zag**
- {
- int y=splay[rt].fat;
- PushDown(y);
- PushDown(rt);
- splay[y].chd[kind^]=splay[rt].chd[kind];
- splay[ssplay(rt,kind)].fat=y;
- if(splay[y].fat)//不是一个zig后者zag
- splay[splay[y].fat].chd[ssplay(splay[y].fat,)==y]=rt;//y父节点的(y的左右)孩子
- splay[rt].fat=splay[y].fat;
- splay[rt].chd[kind]=y;
- splay[y].fat=rt;
- PushUp(y);
- return;
- }
- inline void Splay(int rt,int goal)//**关键的伸展操作(双旋)**
- {
- PushDown(rt);
- while(splay[rt].fat!=goal)
- {
- int y=splay[rt].fat;
- if(splay[y].fat==goal)//一次zig/zag
- {
- Rotate(rt,splay[y].chd[]==rt);//rt是否为左孩子
- }
- else
- {
- int kind=(splay[splay[y].fat].chd[]==y?:);//y是否为左孩子
- if(splay[y].chd[kind]==rt)//左孩子的右孩子或者右孩子的左孩子
- {
- Rotate(rt,kind^);
- Rotate(rt,kind);
- }
- else
- {
- Rotate(y,kind);
- Rotate(rt,kind);
- }
- }
- }
- PushUp(rt);
- if(!goal)
- root=rt;//更新根节点
- return;
- }
- inline void Rotateto(int pos,int goal)//**得到第pos个数,并且进行伸展**
- {
- int rt=root;
- PushDown(rt);
- while(splay[ssplay(rt,)].sizee!=pos)
- {
- if(splay[ssplay(rt,)].sizee>pos)
- rt=splay[rt].chd[];
- else
- {
- pos-=(splay[ssplay(rt,)].sizee+);
- rt=splay[rt].chd[];
- }
- PushDown(rt);
- }
- Splay(rt,goal);
- return;
- }
- void Create(int sta,int enn,int &rt,int fa)//建树与添树
- {
- if(sta>enn)
- return;
- int mid=dir(sta+enn,);
- NewNode(rt,fa,num[mid]);
- Create(sta,mid-,splay[rt].chd[],rt);
- Create(mid+,enn,splay[rt].chd[],rt);
- PushUp(rt);//建树与添树时上更新
- return;
- }
- void Init(int n)//初始化
- {
- for(int i=; i<n; ++i)
- scanf("%d",&num[i]);
- splay[].lmax=splay[].rmax=splay[].mmax=-Inf;//可能全为负数
- splay[].chd[]=splay[].chd[]=splay[].fat=;//建立哨兵,避免特判
- splay[].val=splay[].sizee=splay[].sum=tot2=tot=root=;
- splay[].sam=splay[].file=;
- NewNode(root,,);//建立两个哨兵
- NewNode(splay[root].chd[],root,);
- Create(,n-,splay[ssplay(root,)].chd[],splay[root].chd[]);
- PushUp(splay[root].chd[]);//与建树一起的上更新
- PushUp(root);
- return;
- }
- void Insert(int pos,int dig)//在pos与pos+1之间添加
- {
- Rotateto(pos,);//旋转pos位置的值成0的孩子
- Rotateto(pos+,root);
- Create(,dig-,splay[ssplay(root,)].chd[],splay[root].chd[]);//建立
- PushUp(splay[root].chd[]);//更新
- PushUp(root);//下面很多函数都是五行中仅仅修改第三行
- return;
- }
- void Erase(int rt)//回收空间
- {
- if(!rt)
- return;
- memp[++tot2]=rt;
- Erase(splay[rt].chd[]);
- Erase(splay[rt].chd[]);
- return;
- }
- void Delete(int pos,int dig)//删除pos后面dig个
- {
- Rotateto(pos-,);
- Rotateto(pos+dig,root);
- Erase(splay[ssplay(root,)].chd[]);//关键位置
- splay[ssplay(root,)].chd[]=;
- PushUp(splay[root].chd[]);
- PushUp(root);
- return;
- }
- void Make_same(int pos,int dig,int fix)//修改pos后面dig和为fix
- {
- Rotateto(pos-,);
- Rotateto(pos+dig,root);
- sson(splay[ssplay(root,)].chd[],fix);
- PushUp(splay[root].chd[]);
- PushUp(root);
- return;
- }
- void Reverse(int pos,int dig)//翻转pos后面dig个
- {
- Rotateto(pos-,);
- Rotateto(pos+dig,root);
- fson(splay[ssplay(root,)].chd[]);
- PushUp(splay[root].chd[]);
- PushUp(root);
- return;
- }
- int GetSum(int pos,int dig)//计算pos后面dig个数的和
- {
- Rotateto(pos-,);
- Rotateto(pos+dig,root);
- return splay[ssplay(ssplay(root,),)].sum;
- }
- int GetMaxsum(int pos,int dig)//区间最值
- {
- Rotateto(pos-,);
- Rotateto(pos+dig,root);
- return splay[ssplay(ssplay(root,),)].mmax;//注意每次都需要splay一下,保证时间复杂度
- }
- int main()
- {
- int n,m;
- char str[];
- int pos,dig,fix;
- while(~scanf("%d %d",&n,&m))
- {
- Init(n);
- while(m--)
- {
- //debug();
- scanf("%s",str);
- if(!strcmp(str,"INSERT"))//添加一段数
- {
- scanf("%d %d",&pos,&dig);
- for(int i=; i<dig; ++i)
- scanf("%d",&num[i]);
- Insert(pos,dig);
- }
- else if(!strcmp(str,"DELETE"))//删除一段数
- {
- scanf("%d %d",&pos,&dig);
- Delete(pos,dig);
- }
- else if(!strcmp(str,"MAKE-SAME"))//修改
- {
- scanf("%d %d %d",&pos,&dig,&fix);
- Make_same(pos,dig,fix);
- }
- else if(!strcmp(str,"REVERSE"))//翻转
- {
- scanf("%d %d",&pos,&dig);
- Reverse(pos,dig);
- }
- else if(!strcmp(str,"GET-SUM"))//求和
- {
- scanf("%d %d",&pos,&dig);
- printf("%d\n",GetSum(pos,dig));
- }
- else//最大子序列
- {
- printf("%d\n",GetMaxsum(,splay[root].sizee-));//注意有两个哨兵
- }
- }
- }
- return ;
- }
HYSBZ 1500 维修数列(伸展树模板)的更多相关文章
- [BZOJ 1500]维修数列 [Splay Tree从进阶到住院]
历尽艰辛终于A掉了这题QwQ 贴COGS评论区几句话=.= 策爷:"splay/块状链表的自虐题.".深刻理解到如果没有M倾向就不要去写这题了.. -Chenyao2333 记得b ...
- bzoj 1500 维修数列
splay乱搞. 调了两个多小时...这辈子再也不想写splay了... 维护左边最大连续和右边最大连续,维护两个标记,无脑push_down.push_up就行了. 注意最大连续和至少要包含一个数. ...
- BZOJ 1500 维修数列【Splay】
注意:1,内存限制,所以需要回收删除的点 2,当前节点的左连续区间和最大值=max(左子树的左连续区间和最大值,左子树的总和+当节点的值+max(右子树的左连续区间和最大值,0)):右连续区间和最大值 ...
- splay伸展树模板
普通版本: struct SplayTree { ; ], key[maxn], val[maxn], sz[maxn], lz[maxn], fa[maxn]; , ) { ch[x][]=ch ...
- 【BZOJ】1500: [NOI2005]维修数列
[算法]splay [题解]数据结构 感谢Occult的模板>_<:HYSBZ 1500 维修数列 #include<cstdio> #include<cctype> ...
- wikioi 1396 伸展树(两个模板)
题目描写叙述 Description Tiger近期被公司升任为营业部经理.他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来 ...
- bzoj 1500: [NOI2005]维修数列 splay
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 6556 Solved: 1963[Submit][Status ...
- BZOJ 1500: [NOI2005]维修数列 (splay tree)
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 4229 Solved: 1283[Submit][Status ...
- Splay伸展树入门(单点操作,区间维护)附例题模板
Pps:终于学会了伸展树的区间操作,做一个完整的总结,总结一下自己的伸展树的单点操作和区间维护,顺便给未来的自己总结复习用. splay是一种平衡树,[平均]操作复杂度O(nlogn).首先平衡树先是 ...
随机推荐
- c语言行编辑程序
static.h 头文件 typedef struct bufferStatic{ char *top; char *base; int staticSize; }bufferStatic; type ...
- matlab7.0安装 win7系统详细使用方法附软件下载
MATLAB 7.0下载地址: 百度网盘下载地址:http://pan.baidu.com/share/link?shareid=414204&uk=2769186556 迅雷快传下载地址:h ...
- 内置函数: filter 和 map
内置函数———filter和map filter filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表.接收两个参数,第一个为函数,第二个为序列,序列的每个元素作 ...
- Js用户引导插件bootstrap-tour
1.demo直接贴上来了,有什么不懂的,直接去官网上看,地址:http://bootstraptour.com/. 2.这个bootstrap-tour插件的版本是v0.12.0,复制下来代码,引入库 ...
- 【生产问题】--8KW的数据表导致业务卡顿
问题描述:业务突然变得巨卡 分析思路: (1)分析用户请求进程:查看是否有长期运行霸占锁的情况,或者进程数量巨多.很明显我这里就是巨多,正常情况一般0~40来个的样子,在业务使用高峰期居然达到了140 ...
- 【AWS】AWS云计算赋能数字化转型专题研讨会
点我查看详情 欢迎莅临
- 【整理学习Hadoop】Hadoop学习基础之二:分布式
分布式系统就是将系统的应用层,数据层或其它部分构架成分布(物理和逻辑上的都可以)状(通常是网状).分布式系统通常是为了增强系统的可扩展性.稳定性和执行效率.比如在线游戏通常就是分布系统,里面所谓的 ...
- 通过ip得到所在城市,以及城市所在经纬度坐标(监控系统中用的该代码,小航哥)
监控系统中就是利用的该段代码,实现通过ip得到所在城市,以及城市所在经纬度坐标,最后得以利用echarts实现模拟迁移的效果 api官方介绍: http://lbsyun.baidu.com/inde ...
- pyhton3 configparser模块
1 #!/usr/bin/env python 2 # coding=utf-8 3 __author__ = 'Luzhuo' 4 __date__ = '2017/5/26' 5 # config ...
- 吐槽 MySQL数据库jdbc操作,varchar类型占位符问题——单引号造孽
很长时间不写代码动手能力明显下降很多常见的错误还是经常发生,今天吐血了一次. 简单的坑总是要多跳几次才能甘心.很清晰的记得大学的时候在此坑差点闷死,现在又跳进这个坑了,搞了半天终于知道错在哪里. St ...