codevs 1576 最长上升子序列的线段树优化
题目:codevs 1576 最长严格上升子序列
链接:http://codevs.cn/problem/1576/
优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] 。根据数星星的经验,一个点一个点更新可以解决1到i-1的问题,然后线段树是维护最大值,那么A[j]<A[i]的条件就用查询区间保证,即查询:1到A[i]的f[i]最大值。为了不溢出,因此需要离散化。
附代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 using namespace std; 5 const int maxn=5010; 6 7 int f[maxn],n,maxv[maxn*4]; 8 9 struct u 10 { 11 int v,r; 12 bool operator <(const u &rhs) const 13 { 14 return v<rhs.v; 15 } 16 }A[maxn]; 17 18 bool cmp(u a,u b) 19 { 20 return a.r<b.r; 21 } 22 23 int p,v; 24 void update(int o,int L,int R) 25 { 26 if(L==R) maxv[o]=v; 27 else 28 { 29 int M=(L+R)/2; 30 if(p<=M) update(o*2,L,M); else update(o*2+1,M+1,R); 31 maxv[o]=max(maxv[o*2],maxv[o*2+1]); 32 } 33 } 34 35 int y1,y2,ans; 36 void query(int o,int L,int R) 37 { 38 if(y1<=L && R<=y2) ans=max(ans,maxv[o]); 39 else 40 { 41 int M=(L+R)/2; 42 if(y1<=M) query(o*2,L,M); 43 if(y2>M) query(o*2+1,M+1,R); 44 } 45 } 46 47 int main() 48 { 49 cin>>n; 50 for(int i=1;i<=n;i++) 51 { 52 cin>>A[i].v; 53 f[i]=1; 54 A[i].r=i; 55 } 56 57 sort(A+1,A+n+1); 58 for(int i=1;i<=n;i++) A[i].v=i; 59 sort(A+1,A+n+1,cmp); 60 61 p=A[1].v,v=1; 62 update(1,1,n); 63 for(int i=2;i<=n;i++) 64 { 65 y1=1,y2=A[i].v,ans=0; 66 query(1,1,n); 67 f[i]=ans+1; 68 p=A[i].v,v=f[i]; 69 update(1,1,n); 70 } 71 cout<<f[n]; 72 return 0; 73 }