SPLAY,LCT学习笔记(二)
能够看到,上一篇的代码中有一段叫做find我没有提到,感觉起来也没有什么用,那么他的存在意义是什么呢?
接下来我们来填一下这个坑
回到我们的主题:NOI 2005维修数列
我们刚刚讨论了区间翻转的操作方法,接下来我们来考虑区间插入和区间删除的方法。
有了上一篇的铺垫,大家应该能看都,这两个操作方法是一致的,就是将区间前驱转到根,后继转到根的右节点。
所以当我们插入一段区间的时候,我们还是把这个区间的前驱和后继转上去,然后把这段区间插到左子树就可以了
等等,怎么插?
一个一个往上扔?
这显然是不合理的。
合理的方法是,将所有数据先建成一棵树,然后直接把这棵树挂到左子节点上即可。
可是这样时间不会爆吗?
当然不会!
为什么?
我们稍微分析一下,每次建树都是O(nlog2n)的,而插入数字总数不超过4000000,也就是说,即使我们一次性将这些数全插进去,也仅仅会有点卡常
何况正常情况下这么多东西不会一口气插进去,所以是完全不必担心时间炸掉的。
那么删除一段区间也是同理了。
再往后,就是区间赋值了。
区间赋值和区间翻转很接近,但是如果进行了区间赋值,那区间翻转就没有进行的必要了,所以操作的时候注意一下顺序就好。
然后是维护区间和和维护最大子段和
区间求和操作类似线段树,我们用一个点维护他子树的和,向上更新即可
最大子段和类似小白逛公园,由维护左联通,右联通和全区间的最优解,向上合并即可
(所以有人吐槽,说这题是1/6的线段树,1/6小白逛公园,1/6文艺平衡树,还有1/2不知道什么玩意的东西)
还需要一些细节问题:
虽然说要扔进去4000000个数,但事实上,一个序列中不过500000个数,所以SPLAY空间开到500000左右就行
可是剩下那些如果直接扔就立刻RE啦
所以我们开一个队列,把原来删除的数的编号保存起来,做一个清理垃圾的机制,这样就可以保证空间不爆炸了。
那么这样的话,每个根的编号就会有变化,所以我们要用一个映射getid,记录多余的编号
可是如果这么操作,编号是很混乱的,所以我们就需要上面提到的find函数来查到这个端点在SPLAY中真实的根。
最后是恶心的代码...
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define INF 0x3f3f3f3f
#define ls tree[rt].lson
#define rs tree[rt].rson
using namespace std;
struct SPLAY
{
int lson;
int rson;
int maxval;
int maxls;
int maxrs;
int s;
int val;
bool ctag;
bool ttag;
int fa;
int huge;
}tree[1000005];
int getid[500005];
int a[500005];
int cnt=0;
int rot;
int n,m;
char s[10];
queue <int> M;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void update(int rt)
{
tree[rt].s=tree[ls].s+tree[rs].s+tree[rt].val;
tree[rt].huge=tree[ls].huge+tree[rs].huge+1;
tree[rt].maxval=max(tree[ls].maxval,max(tree[rs].maxval,tree[ls].maxrs+tree[rs].maxls+tree[rt].val));
tree[rt].maxls=max(tree[ls].maxls,tree[ls].s+tree[rt].val+tree[rs].maxls);
tree[rt].maxrs=max(tree[rs].maxrs,tree[rs].s+tree[rt].val+tree[ls].maxrs);
}
void cleanrubbish(int rt)
{
if(ls)
{
cleanrubbish(ls);
}
if(rs)
{
cleanrubbish(rs);
}
M.push(rt);
tree[rt].ttag=tree[rt].ctag=tree[rt].fa=ls=rs=0;
}
void pushdown(int rt)
{
if(tree[rt].ctag)
{
tree[rt].ctag=tree[rt].ttag=0;
if(ls)
{
tree[ls].s=tree[rt].val*tree[ls].huge;
tree[ls].ctag=1;
tree[ls].val=tree[rt].val;
}
if(rs)
{
tree[rs].s=tree[rt].val*tree[rs].huge;
tree[rs].ctag=1;
tree[rs].val=tree[rt].val;
}
if(tree[rt].val>=0)
{
if(ls)
{
tree[ls].maxval=tree[ls].maxls=tree[ls].maxrs=tree[ls].s;
}
if(rs)
{
tree[rs].maxval=tree[rs].maxls=tree[rs].maxrs=tree[rs].s;
}
}else
{
if(ls)
{
tree[ls].maxls=tree[ls].maxrs=0;
tree[ls].maxval=tree[ls].val;
}
if(rs)
{
tree[rs].maxls=tree[rs].maxrs=0;
tree[rs].maxval=tree[rs].val;
}
}
}
if(tree[rt].ttag)
{
tree[rt].ttag=0;
tree[ls].ttag^=1;
tree[rs].ttag^=1;
swap(tree[ls].maxls,tree[ls].maxrs);
swap(tree[rs].maxls,tree[rs].maxrs);
swap(tree[ls].lson,tree[ls].rson);
swap(tree[rs].lson,tree[rs].rson);
}
}
int findf(int rt,int v)
{
pushdown(rt);
if(tree[ls].huge+1==v)
{
return rt;
}else if(tree[ls].huge>=v)
{
return findf(ls,v);
}else
{
return findf(rs,v-tree[ls].huge-1);
}
}
void rotate(int st,int &to)
{
int v1=tree[st].fa;
int v2=tree[v1].fa;
int ltyp;
if(tree[v1].rson==st)
{
ltyp=1;
}else
{
ltyp=0;
}
if(v1==to)
{
to=st;
}else
{
if(tree[v2].lson==v1)
{
tree[v2].lson=st;
}else
{
tree[v2].rson=st;
}
}
if(ltyp)
{
tree[tree[st].lson].fa=v1;
tree[v1].fa=st;
tree[v1].rson=tree[st].lson;
tree[st].lson=v1;
tree[st].fa=v2;
}else
{
tree[tree[st].rson].fa=v1;
tree[v1].fa=st;
tree[v1].lson=tree[st].rson;
tree[st].rson=v1;
tree[st].fa=v2;
}
update(v1);
update(st);
}
void splay(int st,int &to)
{
while(st!=to)
{
int v1=tree[st].fa;
int v2=tree[v1].fa;
if(v1!=to)
{
if((tree[v2].lson==v1&&tree[v1].lson!=st)||(tree[v2].rson==v1&&tree[v1].rson!=st))
{
rotate(st,to);
}else
{
rotate(v1,to);
}
}
rotate(st,to);
}
}
int split(int st,int len)
{
int v1=findf(rot,st);
int v2=findf(rot,st+len+1);
splay(v1,rot);
splay(v2,tree[v1].rson);
return tree[v2].lson;
}
void reverse(int st,int len)
{
int v1=split(st,len);
if(!tree[v1].ctag)
{
tree[v1].ttag^=1;
swap(tree[v1].lson,tree[v1].rson);
swap(tree[v1].maxls,tree[v1].maxrs);
update(tree[v1].fa);
update(tree[tree[v1].fa].fa);
}
}
void buildtree(int l,int r,int f)
{
int mid=(l+r)>>1;
int v1=getid[mid];
int v2=getid[f];
if(l==r)
{
tree[v1].lson=tree[v1].rson=0;
tree[v1].maxval=tree[v1].s=tree[v1].val=a[l];
tree[v1].maxls=tree[v1].maxrs=max(tree[v1].s,0);
tree[v1].ctag=tree[v1].ttag=0;
tree[v1].huge=1;
}
if(mid>l)
{
buildtree(l,mid-1,mid);
}
if(mid<r)
{
buildtree(mid+1,r,mid);
}
tree[v1].val=a[mid];
tree[v1].fa=v2;
update(v1);
if(mid<f)
{
tree[v2].lson=v1;
}else
{
tree[v2].rson=v1;
}
}
void ins(int st,int len)
{
for(int i=1;i<=len;i++)
{
a[i]=read();
}
for(int i=1;i<=len;i++)
{
if(!M.empty())
{
getid[i]=M.front();
M.pop();
}else
{
getid[i]=++cnt;
}
}
buildtree(1,len,0);
int v=getid[(1+len)>>1];
int v1=findf(rot,st+1);
int v2=findf(rot,st+2);
splay(v1,rot);
splay(v2,tree[rot].rson);
tree[v2].lson=v;
tree[v].fa=v2;
update(v2);
update(v1);
}
void del(int st,int len)
{
int v1=split(st,len);
int f=tree[v1].fa;
tree[f].lson=0;
cleanrubbish(v1);
update(f);
update(tree[f].fa);
}
void changesame(int st,int len,int v)
{
int v1=split(st,len);
tree[v1].val=v;
tree[v1].ctag=1;
tree[v1].s=tree[v1].huge*v;
if(v>=0)
{
tree[v1].maxls=tree[v1].maxrs=tree[v1].maxval=tree[v1].s;
}else
{
tree[v1].maxls=tree[v1].maxrs=0;
tree[v1].maxval=v;
}
update(tree[v1].fa);
update(tree[tree[v1].fa].fa);
}
int query(int st,int len)
{
int v1=split(st,len);
return tree[v1].s;
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("my.out","w",stdout);
n=read(),m=read();
tree[0].maxval=a[1]=a[n+2]=-INF;
for(int i=1;i<=n;i++)
{
a[i+1]=read();
getid[i]=i;
}
getid[n+1]=n+1;
getid[n+2]=n+2;
buildtree(1,n+2,0);
rot=(n+3)>>1,cnt=n+2;
while(m--)
{
scanf("%s",s);
if(s[0]=='I')
{
int st=read(),len=read();
ins(st,len);
}else if(s[0]=='D')
{
int st=read(),len=read();
del(st,len);
}else if(s[0]=='R')
{
int st=read(),len=read();
reverse(st,len);
}else if(s[0]=='G')
{
int st=read(),len=read();
printf("%d\n",query(st,len));
}else if(s[2]=='X')
{
printf("%d\n",tree[rot].maxval);
}else
{
int st=read(),len=read(),v=read();
changesame(st,len,v);
}
}
return 0;
}
SPLAY,LCT学习笔记(二)的更多相关文章
- LCT 学习笔记
LCT学习笔记 前言 自己定的学习计划看起来完不成了(两天没学东西,全在补题),决定赶快学点东西 于是就学LCT了 简介 Link/Cut Tree是一种数据结构,我们用它解决动态树问题 但是LCT不 ...
- WPF的Binding学习笔记(二)
原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...
- AJax 学习笔记二(onreadystatechange的作用)
AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...
- JMX学习笔记(二)-Notification
Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
- Java IO学习笔记二
Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...
- 《SQL必知必会》学习笔记二)
<SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...
- NumPy学习笔记 二
NumPy学习笔记 二 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.<数学分 ...
- Learning ROS for Robotics Programming Second Edition学习笔记(二) indigo tools
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
随机推荐
- SVM的两个参数 C 和 gamma
SVM模型有两个非常重要的参数C与gamma.其中 C是惩罚系数,即对误差的宽容度.c越高,说明越不能容忍出现误差,容易过拟合.C越小,容易欠拟合.C过大或过小,泛化能力变差 gamma是选择RBF函 ...
- MySQL_异常
问题1 描述:在连接MYSQL数据库时出现问题:“ERROR 2003 (HY000): Can’t connect to MySQL server on ‘localhost’ (10061)” 分 ...
- 学习windows编程 day3 之窗口绘画一:点线绘制
#include <windows.h> #include <math.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT message, ...
- Spark记录-大数据简介
什么是大数据 大数据(big data),指无法在一定时间范围内用常规软件工具进行捕捉.管理和处理的数据集合,是需要新处理模式才能具有更强的决策力.洞察发现力和流程优化能力的海量.高增长率和多样化的信 ...
- 所有HTTP请求参数及报文查看SERVLET【原】
HttpRequestServlet.java 说明: 用于接受所有http形式的请求,并把接受到的request中param及getInputStream全打印出来. package king.se ...
- UESTC - 1168 凤神与狗
原题链接 凤神隐居山林,与猫狗为伴.起初,他拥有cc只猫和dd只狗.每天下午他随机从中选择一只出去游玩并且晚上归来.如果他带的是狗,则第二天早上狗的数量增加ww只,否则,猫的数量增加ww只.由于凤神特 ...
- python 小爬虫爬取博客文章初体验
最近学习 python 走火入魔,趁着热情继续初级体验一下下爬虫,以前用 java也写过,这里还是最初级的爬取html,都没有用html解析器,正则等...而且一直在循环效率肯定### 很低下 imp ...
- Cmder-控制台模拟器
Cmder是一个软件包,由于在Windows上缺少漂亮的控制台模拟器而纯粹受挫. 它基于令人惊叹的软件,并采用Monokai配色方案和自定义快速布局,从一开始就看起来很性感. 首先,展示一下界面,和W ...
- Jquery中click事件重复执行的问题
平常没注意事件绑定问题,在此注意一下: function testClick(obj){ $("select").off().on("click", funct ...
- Newtonsoft.Json 两个Attribute含义
1.[JsonIgnore] 看名字就知道了,通过这个Attribute可以忽略序列化某个实体类字段 2.[JsonProperty("Font")] 设置序列化到json中的实际 ...