[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)

Output

N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。

Sample Input

3

0 0 2

Sample Output

1

1

2

HINT

100%的数据 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、对题的辨析能力还需加强,要多想多观察,找到不被影响的东西

最新文章

  1. BZOJ2408 混乱的置换
  2. Effective C++ -----条款34:区分接口继承和实现继承
  3. LinkedList源码分析
  4. mysql线程缓存和表缓存
  5. 大数据实践:ODI 和 Twitter (一)
  6. 五分钟solr4.5教程(搭建、运行)
  7. 关于matlab中textread
  8. sql中NULL的问题
  9. tablbView中section的间距
  10. [C++ Calculator 项目] 初试
  11. Day25 前端自学日记——入坑记
  12. 基于HTTP头部的注入
  13. Spring学习札记(一)
  14. SSH整合方案一(带有hibernate.cfg.xml)
  15. gulp的安装与使用【附配置代码】
  16. TypeError: Cannot read property &#39;length&#39; of null
  17. Failed to load ApplicationContext
  18. .Net Core 本地化&amp;全球化 实践
  19. ASP.NET Web API 入门 (API接口、寄宿方式、HttpClient调用)
  20. 解决Keyboard遮盖输入的几种办法

热门文章

  1. 一个初学者的辛酸路程-初识Django
  2. jQuery制作table表格布局插件带有列左右拖动效果
  3. 软件工程概论课堂测试一————添加新课程(web)
  4. json字符串数组判断其中
  5. J2EE的十三种技术——JNDI
  6. $this和self、parent这三个关键词分别代表什么?在哪些场合下使用?
  7. Python字符串相关
  8. BZOJ1004 [HNOI2008]Cards 【burnside定理 + 01背包】
  9. delete zone and cfgsave on brocade by CMD
  10. Topcoder SRM 600 div1题解