Portal --> 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)\)的

​  然后就十分愉快地做完啦

  

  代码大概长这个样子

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. const int MAXN=100010,SEG=MAXN*4;
  6. namespace Seg{/*{{{*/
  7. int ch[SEG][2],sum[SEG],mx[SEG];
  8. int n,tot;
  9. void pushup(int x){
  10. sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
  11. mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);
  12. }
  13. void _build(int x,int l,int r){
  14. sum[x]=0; mx[x]=0;
  15. if (l==r){sum[x]=0; return;}
  16. int mid=l+r>>1;
  17. ch[x][0]=++tot; _build(ch[x][0],l,mid);
  18. ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
  19. pushup(x);
  20. }
  21. void build(int _n){n=_n; tot=1; _build(1,1,n);}
  22. void _update(int x,int d,int lx,int rx,int delta){
  23. if (lx==rx) {sum[x]+=delta;mx[x]+=delta;return;}
  24. int mid=lx+rx>>1;
  25. if (d<=mid) _update(ch[x][0],d,lx,mid,delta);
  26. else _update(ch[x][1],d,mid+1,rx,delta);
  27. pushup(x);
  28. }
  29. void update(int d,int delta){_update(1,d,1,n,delta);}
  30. int _query_mx(int x,int l,int r,int lx,int rx){
  31. if (l<=lx&&rx<=r) return mx[x];
  32. int mid=lx+rx>>1,ret=0;
  33. if (l<=mid) ret=max(ret,_query_mx(ch[x][0],l,r,lx,mid));
  34. if (r>mid) ret=max(ret,_query_mx(ch[x][1],l,r,mid+1,rx));
  35. return ret;
  36. }
  37. int query(int l,int r){return _query_mx(1,l,r,1,n);}
  38. int _get_loc(int x,int lx,int rx,int k){
  39. if (lx==rx) return lx;
  40. int mid=lx+rx>>1;
  41. if (sum[ch[x][0]]>=k) return _get_loc(ch[x][0],lx,mid,k);
  42. else return _get_loc(ch[x][1],mid+1,rx,k-sum[ch[x][0]]);
  43. }
  44. int get_loc(int k){return _get_loc(1,1,n,k);}
  45. };/*}}}*/
  46. int loc[MAXN],a[MAXN],b[MAXN];
  47. int n,m,ans;
  48. int main(){
  49. #ifndef ONLINE_JUDGE
  50. freopen("a.in","r",stdin);
  51. #endif
  52. scanf("%d",&n);
  53. for (int i=1;i<=n;++i) scanf("%d",b+i),++b[i];
  54. Seg::build(n);
  55. for (int i=1;i<=n;++i) Seg::update(i,1);
  56. for (int i=n;i>=1;--i){
  57. loc[i]=Seg::get_loc(b[i]);
  58. Seg::update(loc[i],-1);
  59. }
  60. for (int i=1;i<=n;++i) a[loc[i]]=i;
  61. Seg::build(n);
  62. ans=0;
  63. int tmp;
  64. for (int i=1;i<=n;++i){
  65. if (loc[i]>1)
  66. tmp=Seg::query(1,loc[i]-1);
  67. else
  68. tmp=0;
  69. Seg::update(loc[i],tmp+1);
  70. ans=max(ans,tmp+1);
  71. printf("%d\n",ans);
  72. }
  73. }

【bzoj3173】最长上升子序列的更多相关文章

  1. [bzoj3173]最长上升子序列_非旋转Treap

    最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...

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

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

  3. [BZOJ3173][Tjoi2013]最长上升子序列

    [BZOJ3173][Tjoi2013]最长上升子序列 试题描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上 ...

  4. 【LG4309】【BZOJ3173】[TJOI2013]最长上升子序列

    [LG4309][BZOJ3173][TJOI2013]最长上升子序列 题面 洛谷 BZOJ 题解 插入操作显然用平衡树就行了 然后因为后面的插入对前面的操作无影响 就直接在插入完的序列上用树状数组求 ...

  5. BZOJ3173 TJOI2013最长上升子序列(Treap+ZKW线段树)

    传送门 Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input ...

  6. bzoj3173[Tjoi2013]最长上升子序列 平衡树+lis

    3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2253  Solved: 1136[Submit][S ...

  7. bzoj千题计划316:bzoj3173: [Tjoi2013]最长上升子序列(二分+树状数组)

    https://www.lydsy.com/JudgeOnline/problem.php?id=3173 插入的数是以递增的顺序插入的 这说明如果倒过来考虑,那么从最后一个插入的开始删除,不会对以某 ...

  8. BZOJ3173:[TJOI2013]最长上升子序列(Splay)

    Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一 ...

  9. bzoj3173: [Tjoi2013]最长上升子序列(fhqtreap)

    这题用fhqtreap可以在线. fhqtreap上维护以i结尾的最长上升子序列,数字按从小到大加入, 因为前面的数与新加入的数无关, 后面的数比新加入的数小, 所以新加入的数对原序列其他数的值没有影 ...

随机推荐

  1. Python中abs()和math.fabs()区别

    描述:Python中fabs(x)方法返回x的绝对值.虽然类似于abs()函数,但是两个函数之间存在以下差异: abs()是一个内置函数,而fabs()在math模块中定义的. fabs()函数只适用 ...

  2. Openstack 10 云环境安装

    概述 资源规划 Undercloud Installation Overcloud Installation Trouble Shooting 附录 本指南介绍了如何使用 Red Hat OpenSt ...

  3. boot,rebuild,resize,migrate有关的scheduler流程

    代码调用流程: 1. nova.scheduler.client.query.SchedulerQueryClient#select_destinations 2. nova.scheduler.rp ...

  4. IncDec序列:差分+贪心

    IncDec序列 题目描述: 给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间[l,r],使下标在这个区间内的数都加一或者都减一. 求至少需要多少次操作才能使数列中的所有数都一样 ...

  5. 获取label标签内for的属性值-js

    <body> <div class="row_2" id="ass"> <label for="aaa"> ...

  6. Twitter推广消息可使品牌线下销售额增长三成

    新浪科技讯 北京时间8月9日上午消息,Twitter周四宣布,该公司的推广消息(Promoted Tweet)可以让品牌的线下销售增长29%. 此外,Twitter当天还推出了一个新项目,让品牌可以追 ...

  7. Python学习小目录汇总

    python其他知识目录 python基础知识-1 1.typora软件使用 2.python解释器安装 3.Python解释器环境变量添加 4.计算机编码知识: 5.输出print(): 6.变量 ...

  8. git blame 查看某行代码提交记录

    1. 在当前git项目目录下执行 git blame -L 38,38 <filename> 例子:  git blame -L 38,38 src/component/BarCode/i ...

  9. 调试和开发npm模块的方式

    ln -s(软连接) 假设my-project是运行npm模块的项目,vue-router是我们需要调试的npm模块 将vue-router下载到与my-project同级目录中. git clone ...

  10. Python中的构造函数

    Python中的构造函数是__init__函数.在Python中,子类如果定义了构造函数,而没有调用父类的,那么Python不会自动调用,也就是说父类的构造函数不会执行. 比如有test.py的mod ...