[loj6088]可持久化最长不降子序列

考虑二分求LIS的过程,就是维护一个序列,其中第i个数表示长度为i的最小结尾,而插入操作就是查找第一个大于x的位置并替换掉

用线段树维护,二分的过程也可以用线段树来完成,对线段树可持久化即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 500005
 4 #define mid (l+r>>1)
 5 int B,V,n,p,x,y,r[N],ans[N],f[N*30],ls[N*30],rs[N*30];
 6 int copy(int k){
 7     f[++V]=f[k];
 8     ls[V]=ls[k];
 9     rs[V]=rs[k];
10     return V;
11 }
12 void build(int &k,int l,int r){
13     f[k=++V]=0x3f3f3f3f;
14     if (l==r){
15         if (!l)f[k]=-0x3f3f3f3f;
16         return;
17     }
18     build(ls[k],l,mid);
19     build(rs[k],mid+1,r);
20     f[k]=max(f[ls[k]],f[rs[k]]);
21 }
22 void update(int &k,int l,int r,int x,int y){
23     k=copy(k);
24     if (l==r){
25         f[k]=y;
26         return;
27     }
28     if (x<=mid)update(ls[k],l,mid,x,y);
29     else update(rs[k],mid+1,r,x,y);
30     f[k]=max(f[ls[k]],f[rs[k]]);
31 }
32 int query(int k,int l,int r,int x){
33     if (l==r)return l;
34     if (f[ls[k]]>x)return query(ls[k],l,mid,x);
35     return query(rs[k],mid+1,r,x);
36 }
37 int main(){
38     scanf("%d",&n);
39     build(r[0],0,n);
40     for(int i=1;i<=n;i++){
41         scanf("%d%d",&p,&x);
42         if (p)printf("%d\n",ans[B=x]);
43         else{
44             B++;
45             y=query(r[B]=r[B-1],0,n,x);
46             if (y)update(r[B],0,n,y,x);
47             printf("%d\n",ans[B]=max(ans[B-1],y));
48         }
49     }
50 }

原文地址:https://www.cnblogs.com/PYWBKTDA/p/11429806.html

时间: 2024-08-07 03:29:27

[loj6088]可持久化最长不降子序列的相关文章

最长不降子序列

最长不降子序列   原文http://www.cppblog.com/superKiki/archive/2010/08/09/122868.html 这题目是经典的DP题目,也可叫作LIS(Longest Increasing Subsequence)最长上升子序列或者 最长不下降子序列.很基础的题目,有两种算法,复杂度分别为O(n*logn)和O(n^2) . 一.问题描述 设有由n个不相同的整数组成的数列,记为: a(1).a(2).--.a(n)且a(i)<>a(j) (i<&g

HDU 1025-Constructing Roads In JGShining&#39;s Kingdom(最长不降子序列,线段树优化)

分析: 最长不降子序列,n很大o(n^2)肯定超,想到了小明序列那个题用线段树维护前面的最大值即可 该题也可用二分搜索来做. 注意问题输出时的坑,路复数后加s #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vecto

动态规划-最长非降子序列

有关概念: 最长上升子序列(LIS,Longest Increasing Subsequence),在一个序列中最长的单调递增的子序列 思路: 求LIS通常有O(n2)和O(nlogn)两种算法 (1)O(n2)算法 fi表示以第i个数结尾的LIS长度 对于序列中的一个数i,在i前面枚举数j,j满足比i小且fj最大,将i作为j的后继 伪代码&状态转移方程: f1=1 for i=2...n for j=1...i-1 if(aj<ai)fi=max(fi,fj+1) 最后结果在f1~fn中取

BZOJ 1046 最长不降子序列(nlogn)

nlogn的做法就是记录了在这之前每个长度的序列的最后一项的位置,这个位置是该长度下最后一个数最小的位置.显然能够达到最优. BZOJ 1046中里要按照字典序输出序列,按照坐标的字典序,那么我萌可以把序列先倒着做最长下降子序列,然后我萌就可以知道以a[i]为开头的最长的长度了.每次扫一遍记录答案即可. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algori

【一维偏序】【最长上升子序列】【最长非降子序列】

两种方法,都是nlogn 树状数组型 #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int N=100003,M=50003; int d[N];//原数组 int f[M]; int n,big; int lowbit(int x) { return x&(-x); } //用于求上升序列 int

uvalive 6122 最长不降子序列

因为数据量非常小(n<=10),所以可以用dfs枚举每个长方体的状态,然后求LIS. 1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 7 const int N = 10; 8 int dp[N]; 9 int n, ans; 10 11 struct T 12 { 13 int

最长非降/下降子序列问题(DP)(待续...)

注意:抽象成以下描述即为最长非降/下降子序列问题(一维状态) 问题描述:在一个无序的序列a1,a2,a3,a4…an里,找到一个最长的序列满足:(不要求连续) ai<=aj<=ak…<=am,且i<j<k…<m.(最长非降子序列) 或 ai>aj>ak…>am,且i<j<k…<m.(最长下降子序列). 问题分析:(以最长非降子序列为例) 考虑状态数组opt[maxn]; 其中opt[i]表示a[i]时可与之前元素构成非降子序列的最大长

动态规划——最长不下降子序列(LIS)

最长不降子序列是这样一个问题: 下面介绍动态规划的做法. 令 dp[i] 表示以 A[i] 结尾的最长不下降序列长度.这样对 A[i] 来说就会有两种可能: 如果存在 A[i] 之前的元素 A[j] (j<i),使得 A[j]≤A[i] 且 dp[j]+1>dp[i],那么就把 A[i] 跟在以 A[j] 结尾的 LIS 后面,形成一条更长的不下降子序列(令 dp[i]=dp[j]+1). 如果 A[i] 之前的元素都比 A[i] 大,那么 A[i] 就只好自己形成一条 LIS,但是长度为 1

最长上升非降子序列的长度动态规划

第一种dp从后往前: dp[i]表示以a[i]为起点的最长上升非降子序列的长度 a[8]={10,2,2,4,12,23,34,2} dp[8]={4,6,5,4,3,2,1,1}; 代码实现: 1 #include<bits/stdc++.h> 2 using namespace std; 3 void logest_increase_sub(const int*a,int ssize) 4 { 5 int *dp=new int[ssize](); 6 int *p=new int[ssi