【bzoj3173】【Tjoi2013】【最长上升子序列】treap+dp二分优化
来源:互联网 发布:听歌软件免费 编辑:程序博客网 时间:2024/06/06 10:52
[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]最长上升子序列 dp Treap
- 【bzoj3173】[Tjoi2013]最长上升子序列 Treap
- BZOJ3173 TJOI2013最长上升子序列(Treap+ZKW线段树)
- BZOJ3173: [Tjoi2013]最长上升子序列 Treap 平衡树
- BZOJ3173: [Tjoi2013]最长上升子序列 Treap+树状数组
- BZOJ3173 [Tjoi2013]最长上升子序列
- [bzoj3173][TJOI2013]最长上升子序列
- 【bzoj3173】: [Tjoi2013]最长上升子序列
- bzoj3173【TJOI2013】最长上升子序列
- bzoj3173: [Tjoi2013]最长上升子序列
- BZOJ3173: [Tjoi2013]最长上升子序列
- 【bzoj3173】[Tjoi2013]最长上升子序列
- bzoj3173: [Tjoi2013]最长上升子序列
- BZOJ3173 [Tjoi2013]最长上升子序列
- bzoj3173: [Tjoi2013]最长上升子序列
- BZOJ3173[最长上升子序列] Treap+LIS
- BZOJ3173 [Tjoi2013]最长上升子序列(离线处理+Treap+LIS)
- 一些资源以及读书总结
- mysql中类型长度以及text和varchar的区别
- Linux基础(2)
- Javascript实现三级联动
- 推送实现机制
- 【bzoj3173】【Tjoi2013】【最长上升子序列】treap+dp二分优化
- 链表-->增-->删-->查-->改-->排序
- 《解析深度学习:语音识别实践》读书总结
- 2656: [Zjoi2012]数列(sequence)
- 关键词private
- Linux 压缩解压缩命令汇总
- 简单插入排序(Insertion Sort)——插入类排序法(Java实现)
- 菜鸟学习计划
- 作为产品经理,常见的这四种产品需求你是怎么处理的呢?