【bzoj3173】【Tjoi2013】【最长上升子序列】treap+dp二分优化
[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61560361
向大(hei)佬(e)实力学(di)习(tou)
Description
给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
Input第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)
OutputN行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。
Sample Input3
0 0 2
Sample Output1
1
2
HINT100%的数据 n<=100000
其实这道题算是一道裸题了,拿来练习一下模板。看到这种活动的插入,就能立即想到平衡树。至于最长上升子序列,如果每插入一次就求一次,再优化都要超时。于是我们就找找性质,发现:由于是有序插入,后插入的一定大,那么每插入一个点,以此点结尾的最长上升子序列就不受后面点的干扰。那么在插入完毕后求一次最长上升子序列就可以了。之后的输出需注意要求的是整个数列的答案,还要在小于等于插入数的dp数组中求max。因为这个我又wa了一遍
至于二分优化,其实也算是练手。简单梳理一下,也便自己理解更透彻。要开一个单调栈(?),存两个元素,一个为值,一个为下标。
以 6 2 1 4 3 为例,从左往右扫
6进栈 >6(1)
dp[1]=1;
2比栈顶元素小,要去替换,二分到6,替换>2(2)
dp[2]=1;
1同理>1(3)
dp[3]=1;
4>1,4直接进栈>1(3) 4(4)
dp[4]=dp[3]+1=2;
3二分换4,>1(3) 3(5)
dp[5]=dp[3]+1=2;
最后再for一遍找max,总o(log n)
这道题因为比较特殊,数字不重复,且按序插入,所以直接以数字本身作为下标。
求最长上升子序列还可以用树状数组优化,哪天再遇到这样的题再复习树状数组优化吧!
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std ;
const int N=100000+5;
int n,x;
struct Node{
Node *ch[2];
int v,r,siz;
int cmp(int x){
return x <= ch[0]->siz ? 0 : 1;
}
}*root,*null,pool[N],*tail=pool;
int c[N],top=0,dp[N];
Node *newnode(){
Node *rt=++tail;
rt->ch[0]=rt->ch[1]=null;
rt->v=rt->r=rt->siz=0;
return rt;
}
void rotate(Node *&nd,int d){
Node *tp=nd->ch[d];
nd->ch[d]=tp->ch[d^1];tp->ch[d^1]=nd;
nd->siz=nd->ch[0]->siz+nd->ch[1]->siz+1;
tp->siz=tp->ch[0]->siz+tp->ch[1]->siz+1;
nd=tp;
}
void insert(Node *&nd,int val,int pos){
if(nd==null){
nd=newnode();
nd->v=val;
nd->siz=1;
nd->r=rand();
return ;
}
int d=nd->cmp(pos);
insert(nd->ch[d],val,d ? pos - nd->ch[0]->siz - 1: pos );
if(nd->ch[d]->r > nd->r ){
rotate(nd,d);
}
nd->siz=nd->ch[0]->siz+nd->ch[1]->siz+1;
}
int get_dp(int x){
int rt;
if(x>c[top]){
c[++top]=x;
return dp[c[top-1]]+1;
}
int le=0,ri=top;
while(le<ri){
int mid=(le+ri)>>1;
if(c[mid]>x) ri=mid;
if(c[mid]<=x) le=mid+1;
}
c[le]=x;
return dp[c[le-1]]+1;
}
void query(Node *nd){
if(nd==null) return ;
query(nd->ch[0]);
dp[nd->v]=get_dp(nd->v);
query(nd->ch[1]);
}
int main(){
srand(23425546);
null=++tail;
null->ch[0]=null->ch[1]=null;
null->v=null->r=null->siz=0;
root=null;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
insert(root,i,x);
}
query(root);
for(int i=1;i<=n;i++){
dp[i]=max(dp[i-1],dp[i]);
printf("%d\n",dp[i]);
}
return 0;
}
总结:
1、对题的辨析能力还需加强,要多想多观察,找到不被影响的东西
【bzoj3173】【Tjoi2013】【最长上升子序列】treap+dp二分优化的更多相关文章
- BZOJ3173 TJOI2013最长上升子序列(Treap+ZKW线段树)
传送门 Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input ...
- [BZOJ3173][Tjoi2013]最长上升子序列
[BZOJ3173][Tjoi2013]最长上升子序列 试题描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上 ...
- BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]
3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1613 Solved: 839[Submit][St ...
- bzoj3173[Tjoi2013]最长上升子序列 平衡树+lis
3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2253 Solved: 1136[Submit][S ...
- bzoj3173: [Tjoi2013]最长上升子序列(树状数组+二分倒推)
3173: [Tjoi2013]最长上升子序列 题目:传送门 题解: 好题! 怎么说吧...是应该扇死自己...看错了两次题: 每次加一个数的时候,如果当前位置有数了,是要加到那个数的前面,而不是直 ...
- 【bzoj3173】[Tjoi2013]最长上升子序列 Treap
题目描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? 输入 第一行一个整数N,表示我们要 ...
- bzoj千题计划316:bzoj3173: [Tjoi2013]最长上升子序列(二分+树状数组)
https://www.lydsy.com/JudgeOnline/problem.php?id=3173 插入的数是以递增的顺序插入的 这说明如果倒过来考虑,那么从最后一个插入的开始删除,不会对以某 ...
- bzoj3173: [Tjoi2013]最长上升子序列(fhqtreap)
这题用fhqtreap可以在线. fhqtreap上维护以i结尾的最长上升子序列,数字按从小到大加入, 因为前面的数与新加入的数无关, 后面的数比新加入的数小, 所以新加入的数对原序列其他数的值没有影 ...
- BZOJ3173:[TJOI2013]最长上升子序列(Splay)
Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一 ...
随机推荐
- GCC 7.3 for Windows
GCC 6.1x Compilers 下载地址1: Mingw gcc 6.30下载 这个是某微软员工编译的版本 MinGW is a port of GCC to Windows. It is fr ...
- U-Net卷积神经网络
由于项目需要,用U-NET跑一个程序来对医学影像进行分割(segmentation),因此跑去看了下这篇论文(paper),下面会介绍一下U-Net的框架及要点,如果哪里有写的不对的,或者好的建议,欢 ...
- H5调试
在PC上的调试 问题:需要调试样式,没有数据不方便调试. 方案:本地mock. EG: chrome书签管理器 →将下面代码存书签里,如下图: javascript: void function() ...
- Android Service完全解析
Service的基本用法 1.新建一个Android项目,新建一个MyService继承自Service,并重写父类的onCreate(),onStartCommand()方法和onDestory() ...
- Java中类的继承深入剖析
在Java开发中,我们常常用到继承这一概念,可以说继承是Java这类面向对象编程语言的基石.正是有了继承这个概念,使得我们可以创建分等级层次的类.今天小编就和大家一起来深入聊聊Java语言的继承. 在 ...
- P4160 [SCOI2009]生日快乐
题目描述 windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕. 现在包括windy,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积的蛋糕. win ...
- BZOJ 2453 维护队列 | 分块
题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2453 题解: 考虑维护每个位置的颜色上一次出现在哪里,计为pre[i],在询问l到r的时候, ...
- 雅礼集训 Day5 T3 题 解题报告
题 题目背景 由于出题人赶时间所以没办法编故事来作为背景. 题目描述 一开始有\(n\)个苹果,\(m\)个人依次来吃苹果,第\(i\)个人会尝试吃\(u_i\)或\(v_i\)号苹果,具体来说分三种 ...
- Glibc说明
Glibc glibc是gnu发布的libc库,也即c运行库.glibc是linux系统中最底层的api(应用程序开发接口),几乎其它任何的运行库都会倚赖于glibc.glibc除了封装linux操作 ...
- 区间(interval)
区间(interval) 题目描述 zht有一个长度为n的排列P,现在zht想知道,有多少个由连续整数组成的区间[l,r][l,r]可以由PP中的两个区间[a,b],[c,d]拼出,其中1≤a≤b&l ...