能够看到,上一篇的代码中有一段叫做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学习笔记(二)的更多相关文章

  1. LCT 学习笔记

    LCT学习笔记 前言 自己定的学习计划看起来完不成了(两天没学东西,全在补题),决定赶快学点东西 于是就学LCT了 简介 Link/Cut Tree是一种数据结构,我们用它解决动态树问题 但是LCT不 ...

  2. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  3. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  4. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  5. JMX学习笔记(二)-Notification

    Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...

  6. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  7. Java IO学习笔记二

    Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...

  8. 《SQL必知必会》学习笔记二)

    <SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...

  9. NumPy学习笔记 二

    NumPy学习笔记 二 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.<数学分 ...

  10. Learning ROS for Robotics Programming Second Edition学习笔记(二) indigo tools

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

随机推荐

  1. java基础-Eclipse开发工具介绍

    java基础-Eclipse开发工具介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 所谓工欲善其事必先利其器,即将身为一名Java开发工程师怎么能没有一款好使的IDE呢?今天就 ...

  2. Scala进阶之路-Spark底层通信小案例

    Scala进阶之路-Spark底层通信小案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Spark Master和worker通信过程简介 1>.Worker会向ma ...

  3. shell函数与数组

    shell函数与数组 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.为什么要使用shell函数 简单的说函数的作用就是把程序里多次调用的相同的代码部分定义成一份,然后起个名字, ...

  4. MYCAT分库分表

    一.整体架构 1.192.168.189.130:mysql master服务,两个数据库db_store.db_user,db_store做了主从复制 db_user: 用户表users为分片表 数 ...

  5. 设计模式---单一职责模式之桥模式(Bridge)

    一:概念 Bridge模式又叫做桥接模式,其实基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任他的主要特点是吧抽象与行为实现分离开来,从而可以保持各部分的独立性以及一对 ...

  6. javascript 事件冒泡与取消冒泡

    事件冒泡: 当一个元素上的事件被触发时,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先中被触发,这一过程被称为事件冒泡. 这个事件从原始祖先开始,一直冒泡到DOM树的最上层.(bug) ...

  7. Linux记录-TCP状态以及(TIME_WAIT/CLOSE_WAIT)分析(转载)

    1.TCP握手定理 2.TCP状态 l  CLOSED:初始状态,表示TCP连接是“关闭着的”或“未打开的”. l  LISTEN :表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接. ...

  8. java RSA 加签验签【转】

    引用自: http://blog.csdn.net/wangqiuyun/article/details/42143957/ java RSA 加签验签 package com.testdemo.co ...

  9. Study 3 —— 表格

    表格基本格式: <table> <tr> <td></td> <td></td> </tr> <tr> ...

  10. SpringJMS解析--监听器

    消息监听器容器是一个用于查看JMS目标等待消息到达的特殊bean,一旦消息到达它就可以获取到消息,并通过调用onMessage()方法将消息传递给一个MessageListener实现.Spring中 ...