【bzoj3173】最长上升子序列
Solution
感觉自己需要智力康复qwq
首先题目给的这个序列肯定是一个\(1-n\)的排列,并且插入的顺序是从小到大
仔细思考一下会发现如果知道了最终的序列,问题就比较好解决了,这里提供一种用线段树的做法:
如果知道了最终的序列,记数字\(i\)在该序列中的位置为\(loc[i]\),那么我们按照\(i\)从小到大的顺序,查询结尾在\([1,loc[i])\)的这段位置中的最长上升子序列的最大值\(mx\),并将\(mx+1\)作为以\(loc[i]\)位置为结尾的答案,插入到线段树中\(loc[i]\)对应的节点里,复杂度是\(O(nlogn)\)
然后现在的问题是怎么求最终的序列
这个可以用平衡树来写,不过其实也可以用线段树来写
考虑反过来确定每一个数在最终序列中的位置,因为是反过来考虑的,所以一开始的时候每一个位置都有一个数,然后我们根据读入的插入位置,按照\(n-1\)的顺序,找到当前这个数的位置,然后将它删掉(也就是对应的线段树节点的\(sum-1\))
具体一点就是比如当前考虑到第\(i\)个数,读入这个数应该要插入在\(a[i]\)的位置后面,也就是应该在当前这个序列的第\(a[i]+1\)个位置,那么找到这个位置,然后把这个位置删掉,这样就可以得到还没有插入这个数之前的序列的位置集合了,这部分的复杂度也是\(O(nlogn)\)的
然后就十分愉快地做完啦
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=100010,SEG=MAXN*4;
namespace Seg{/*{{{*/
int ch[SEG][2],sum[SEG],mx[SEG];
int n,tot;
void pushup(int x){
sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);
}
void _build(int x,int l,int r){
sum[x]=0; mx[x]=0;
if (l==r){sum[x]=0; return;}
int mid=l+r>>1;
ch[x][0]=++tot; _build(ch[x][0],l,mid);
ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
pushup(x);
}
void build(int _n){n=_n; tot=1; _build(1,1,n);}
void _update(int x,int d,int lx,int rx,int delta){
if (lx==rx) {sum[x]+=delta;mx[x]+=delta;return;}
int mid=lx+rx>>1;
if (d<=mid) _update(ch[x][0],d,lx,mid,delta);
else _update(ch[x][1],d,mid+1,rx,delta);
pushup(x);
}
void update(int d,int delta){_update(1,d,1,n,delta);}
int _query_mx(int x,int l,int r,int lx,int rx){
if (l<=lx&&rx<=r) return mx[x];
int mid=lx+rx>>1,ret=0;
if (l<=mid) ret=max(ret,_query_mx(ch[x][0],l,r,lx,mid));
if (r>mid) ret=max(ret,_query_mx(ch[x][1],l,r,mid+1,rx));
return ret;
}
int query(int l,int r){return _query_mx(1,l,r,1,n);}
int _get_loc(int x,int lx,int rx,int k){
if (lx==rx) return lx;
int mid=lx+rx>>1;
if (sum[ch[x][0]]>=k) return _get_loc(ch[x][0],lx,mid,k);
else return _get_loc(ch[x][1],mid+1,rx,k-sum[ch[x][0]]);
}
int get_loc(int k){return _get_loc(1,1,n,k);}
};/*}}}*/
int loc[MAXN],a[MAXN],b[MAXN];
int n,m,ans;
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",b+i),++b[i];
Seg::build(n);
for (int i=1;i<=n;++i) Seg::update(i,1);
for (int i=n;i>=1;--i){
loc[i]=Seg::get_loc(b[i]);
Seg::update(loc[i],-1);
}
for (int i=1;i<=n;++i) a[loc[i]]=i;
Seg::build(n);
ans=0;
int tmp;
for (int i=1;i<=n;++i){
if (loc[i]>1)
tmp=Seg::query(1,loc[i]-1);
else
tmp=0;
Seg::update(loc[i],tmp+1);
ans=max(ans,tmp+1);
printf("%d\n",ans);
}
}
【bzoj3173】最长上升子序列的更多相关文章
- [bzoj3173]最长上升子序列_非旋转Treap
最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...
- [BZOJ3173]最长上升子序列
Problem 给你n个数A1~An,每次将i插入第Ai位后,最后输出每次插入后这个数列的最长上升子序列 Solution 这道题非常的妙.首先如果新加入的这个数构成了最长上升子序列,由于在它插入之前 ...
- [BZOJ3173][Tjoi2013]最长上升子序列
[BZOJ3173][Tjoi2013]最长上升子序列 试题描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上 ...
- 【LG4309】【BZOJ3173】[TJOI2013]最长上升子序列
[LG4309][BZOJ3173][TJOI2013]最长上升子序列 题面 洛谷 BZOJ 题解 插入操作显然用平衡树就行了 然后因为后面的插入对前面的操作无影响 就直接在插入完的序列上用树状数组求 ...
- BZOJ3173 TJOI2013最长上升子序列(Treap+ZKW线段树)
传送门 Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input ...
- bzoj3173[Tjoi2013]最长上升子序列 平衡树+lis
3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2253 Solved: 1136[Submit][S ...
- bzoj千题计划316:bzoj3173: [Tjoi2013]最长上升子序列(二分+树状数组)
https://www.lydsy.com/JudgeOnline/problem.php?id=3173 插入的数是以递增的顺序插入的 这说明如果倒过来考虑,那么从最后一个插入的开始删除,不会对以某 ...
- BZOJ3173:[TJOI2013]最长上升子序列(Splay)
Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一 ...
- bzoj3173: [Tjoi2013]最长上升子序列(fhqtreap)
这题用fhqtreap可以在线. fhqtreap上维护以i结尾的最长上升子序列,数字按从小到大加入, 因为前面的数与新加入的数无关, 后面的数比新加入的数小, 所以新加入的数对原序列其他数的值没有影 ...
随机推荐
- python yagmail第三方库发送邮件--更简洁
1.安装第三方库yagmail: pip install yagmail 2.上代码 import yagmail import os def send_email(): #链接邮箱服务器 serve ...
- JAVA基础学习之路(十二)链表
定义链表的基本结构: class Link {//外部类 //内部类,只为链表类服务 private class Node {//定义节点类 private String data;//保存的数据 p ...
- leetcode个人题解——#48 rotage image
思路:本题要求不能利用额外的二维数组实现旋转,所以重点在于弄清矩阵旋转的数学方法. 我的方法是,首先按照副对角线进行对称,然后按照水平中轴线进行对称即可. class Solution { publi ...
- Hyperledger_Fabric_Model
Hyperledger_Fabric_Model 本部分描述了Hyperledger Fabric的主要设计特点 Assets: 资产定义使得任何东西都可以通过货币值在网络中交易,从食物到老爷车再到期 ...
- JPA error org.hibernate.AnnotationException: No identifier specified for entity
错误:org.hibernate.AnnotationException: No identifier specified for entity 原因:JPA所使用的Entity需要标注@Id,在引用 ...
- sparkSQL中RDD——DataFrame——DataSet的区别
spark中RDD.DataFrame.DataSet都是spark的数据集合抽象,RDD针对的是一个个对象,但是DF与DS中针对的是一个个Row RDD 优点: 编译时类型安全 编译时就能检查出类型 ...
- ES6的新特性(6)——正则的扩展
正则的扩展 RegExp 构造函数 在 ES5 中,RegExp构造函数的参数有两种情况. 第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag). var regex = ne ...
- s2sh乱码一个小处理(新手按流程走)
解决乱码几小点: 1.配置过滤器,可以选择自己写,既然你用的SSH框架就更简单了,直接用Spring的过滤器,web.xml里配置一下即可. 2.Jsp页面设置编码,所有地方都要相同,我习惯用GBK ...
- 《我是IT小小鸟》读后感
<我是IT小小鸟>读后感 说实话,我根本不喜欢看这本书,要不是因为老师要求我也不会去看的,其实当老师提起这本书的时候我还是有点兴趣,去看的,可是看了很多后,觉得这根本不适合我,里面说的都是 ...
- Visual C++ 8.0对象布局
哈哈,从M$ Visual C++ Team的Andy Rich那里又偷学到一招:VC8的隐含编译项/d1reportSingleClassLayout和/d1reportAllClassLayout ...