最长上升子序列 bzoj-3173

    题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度。

    注释:1<=n<=10,000,开始序列为空。

      具体的非旋转Treap的讲解:讲解链接

      想法:显然,我们发现,我每次加入的数一定是当前序列中最大的,所以,刚刚加入的i,要么是当前序列中LIS的结尾,要么不属于LIS。根据这个性质,我们想到:在Treap中维护这样的性质,就是维护每个数加入节点的编号。然后,我们更新新节点的方式就是它的左子树和右子树的LIS取最大+1。其实最重要的就是如何加入这个新的节点?我们引进非旋转Treap。

        非旋转Treap在结构上和Treap一样,都是维护平衡的BST。但是,非旋转Treap在实现上更加暴力和简单。有两个操作,撕裂和合并。

        撕裂?就是去除BST上的一条边,使得原来的非旋转Treap变成两颗树。这样我们就可以对于撕裂开的新子树进行一些单独的处理。例如我们可以撕裂两次,得到一段区间,那么在进行区间反转时就可以仅仅维护一段子树就可以了。

        合并?就是将撕裂之后的子树进行合并即可。这样的话我们对于BST节点的一个权值是随机的,所以我们在合并时还要维护Treap的基本性质。

      这道题的实现和理解无疑是非旋转Treap的裸题,但是非旋转Treap强大的地方已经得到体现。

    最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 300100
#define mp make_pair
using namespace std;
typedef pair<int,int> par;
int n;
int maxx[N],lis[N],size[N],ls[N],rs[N],key[N];
//maxx表示当前节点子树的LIS的长度
//lis表示当前子树中以当前节点结尾的不下降子序列长度
int root;
void update(int x)//这是向上更新
{
maxx[x]=lis[x];
size[x]=size[ls[x]]+size[rs[x]]+1;
maxx[x]=max(maxx[x],max(maxx[ls[x]],maxx[rs[x]]));
}
int lson,rson;
par split(int x,int k)//撕裂操作,返回的是撕裂后两棵新树的根节点,用pair来存储
{
if(!k) return mp(0,x);
lson=ls[x],rson=rs[x];par t;
if(k==size[ls[x]])
{
ls[x]=0;update(x);
return mp(lson,x);
}
if(k==size[ls[x]]+1)
{
rs[x]=0;update(x);
return mp(x,rson);
}
if(k<size[ls[x]])
{
t=split(lson,k);
ls[x]=t.second;update(x);
return mp(t.first,x);
}
t=split(rson,k-size[ls[x]]-1);
rs[x]=t.first;update(x);
return mp(x,t.second);
}
int merge(int x,int y)//合并操作,返回的是合并之后的新树的根节点
{
if(!x|!y)
{
return x|y;
}
if(key[x]<key[y])
{
ls[y]=merge(x,ls[y]);update(y);
return y;
}
rs[x]=merge(rs[x],y);update(x);
return x;
}
int main()
{
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
size[i]=1;
key[i]=rand()*rand();
par t1;
t1=split(root,x);
lis[i]=maxx[i]=maxx[t1.first]+1;
ans=max(ans,lis[i]);
printf("%d\n",ans);
root=merge(merge(t1.first,i),t1.second);
}
return 0;
}

    小结:非旋转Treap相较于Treap所涉及的范围更广,但虽然代码量有所下降,但是细节更多,难度更大。

      错误:split的!k是要进行特判的,不然会死递归。

[bzoj3173]最长上升子序列_非旋转Treap的更多相关文章

  1. [bzoj1500][NOI2005]维修数列_非旋转Treap

    维修数列 bzoj-1500 NOI-2005 题目大意:给定n个数,m个操作,支持:在指定位置插入一段数:删除一个数:区间修改:区间翻转.查询:区间和:全局最大子序列. 注释:$1\le n_{ma ...

  2. [bzoj4864][BeiJing2017Wc]神秘物质_非旋转Treap

    神秘物质 bzoj-4864 BeiJing-2017-Wc 题目大意:给定一个长度为n的序列,支持插入,将相邻两个元素合并并在该位置生成一个指定权值的元素:查询:区间内的任意一段子区间的最大值减最小 ...

  3. [bzoj1552\bzoj2506][Cqoi2014]robotic sort 排序机械臂_非旋转Treap

    robotic sort 排序机械臂 bzoj-1552 bzoj-2506 Cqoi-2014 题目大意:给定一个序列,让你从1到n,每次将[1,p[i]]这段区间反转,p[i]表示整个物品权值第i ...

  4. [bzoj1861][Zjoi2006]Book 书架_非旋转Treap

    Book 书架 bzoj-1861 Zjoi-2006 题目大意:给你一个序列,支持:将指定编号的元素抽出,放到序列顶(底):将指定编号元素左右篡位:查询指定编号元素位置:查询指定数量位置元素编号. ...

  5. [BZOJ3173]最长上升子序列

    Problem 给你n个数A1~An,每次将i插入第Ai位后,最后输出每次插入后这个数列的最长上升子序列 Solution 这道题非常的妙.首先如果新加入的这个数构成了最长上升子序列,由于在它插入之前 ...

  6. [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树

    二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...

  7. BZOJ3224普通平衡树——非旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

  8. BZOJ1500[NOI2005]维修数列——非旋转treap

    题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格 输入 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初 ...

  9. BZOJ1014 JSOI2008 火星人prefix 【非旋转Treap】*

    BZOJ1014 JSOI2008 火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符 ...

随机推荐

  1. JavaScript解决select下拉框中的内容太长显示不全的问题

    JavaScript解决select下拉框中的内容太长显示不全的问题 1.说明 有些情况下,select下拉框的内容过长,导致部分看不见: 现在通过鼠标事件,让下拉框中的内容显示完全 2.实现源码 & ...

  2. INS-20802

    1.错误描述 2.错误原因 安装的是64位数据库,由于在设置数据库配置密码时用的是数字开头,取消时出现这个错误 3.解决办法 重新安装Oracle

  3. Java和Flex整合报错(二)

    1.错误原因 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -nonaming ] { -help ...

  4. Reactor-反应器模式

    Reactor模式:反应器模式,是高性能网络服务器中最为常用的一种模式,libevent,muduo,libuv等网络库都是以 Reactor模式构建.Reactor模式由同步事件多路分解器和具体事件 ...

  5. Linux系统 awk sed R脚本 python脚本传入变量

    sed 传入变量: chrI="chr2";sed -n "/$chrI/p" clippointpos.csv  #变量用$var表示,把sed的单引号变为双 ...

  6. javascript中的内存管理和垃圾回收

    前面的话 不管什么程序语言,内存生命周期基本是一致的:首先,分配需要的内存:然后,使用分配到的内存:最后,释放其内存.而对于第三个步骤,何时释放内存及释放哪些变量的内存,则需要使用垃圾回收机制.本文将 ...

  7. CF AIM Tech Round 3 (Div. 2) D - Recover the String

    模拟 首先可以求出 0 和 1 的个数 之后按照01 10 的个数贪心安排 细节太多 错的都要哭了 #include<bits/stdc++.h> using namespace std; ...

  8. CentOS7.2编译安装PHP7.2.3之史上最详细步骤。

    首先,我们的CentOS版本信息如下: 开始我们的编译. 第一步: 将php安装包安装到/usr/src目录下. cd /usr/src && wget http://cn2.php. ...

  9. 在TextBox中敲击回车执行ASP.NET后台事件

    1.在TextBox中敲击回车执行ASP.NET后台事件   0.说明 页面中有一个用于搜索的TextBox,希望能在输入内容后直接回车开始搜索,而不是手动去点击它旁边的搜索按钮 但因为该TextBo ...

  10. [hihoCoder] 高斯消元·一 [TPLY]

    高斯消元一 题目链接 : http://hihocoder.com/problemset/problem/1195?sid=1269842 很"好aoaoaoaoaoaoa"的高斯 ...