线段树与动态规划的结合 最长上升序列的线段树优化 正在研究

codevs  1576 最长严格上升子序列
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 黄金 Gold

题目描述 Description
给一个数组a1, a2 ... an,找到最长的上升降子序列ab1<ab2< .. <abk,其中b1<b2<..bk。

输出长度即可。

输入描述 Input Description
第一行,一个整数N。

第二行 ,N个整数(N < = 5000)

输出描述 Output Description
输出K的极大值,即最长不下降子序列的长度

样例输入 Sample Input
5
9 3 6 2 7

样例输出 Sample Output
3

此题的转移公式很简单  

要注意到  这个max函数 其实是有A[k]<A[x] 这个限制要求的  所以我们真正需要查询的最大值其实在0----A[x]中 所以我们可以利用线段树做查询 

每次计算出来的值我们可以反向插入到线段树中做记录

第一版的代码没有全部通过 原因是数字超出了线段树可以表示的范围,这个时候离散化就可以派上用场了我们先看第一版残缺代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<queue>
 6 #include<algorithm>
 7 using namespace std;
 8 const int maxn=100000;
 9 const int maxm=5000000;
10 #define lson l,mid,rt<<1
11 #define rson mid+1,r,rt<<1|1
12 #define lrt rt<<1
13 #define rrt rt<<1|1
14 #define getmid int mid=(r+l)/2
15 
16 
17 int n,maxx[maxn*4],tp,ans;
18 
19 void update(int l,int r,int rt,int a,int b)
20 {
21     if(a<=l && a>=r)
22     {
23         maxx[rt]=max(maxx[rt],b);
24         return;
25     }
26     getmid;
27     if(a<=mid) update(lson,a,b);
28     if(a>mid) update(rson,a,b);
29     maxx[rt]=max(maxx[rt],max(maxx[lrt],maxx[rrt]));
30 }
31 
32 
33 int query(int l,int r,int rt,int a,int b)
34 {
35     if(a<=l && b>=r)
36     {
37         return maxx[rt];
38     }
39     getmid;
40     int ans=0;
41     if(a<=mid){
42         ans=max(ans,query(lson,a,b));
43     }
44     if(b>mid){
45         ans=max(ans,query(rson,a,b));
46     }
47     return ans;
48 }
49 
50 int main()
51 {
52     scanf("%d",&n);
53     for(int i=1;i<=n;i++)
54     {
55         scanf("%d",&tp);
56         int t=query(0,maxn,1,1,tp-1)+1;
57         ans=max(ans,t);
58         update(0,maxn,1,tp,t);
59     }    
60     printf("%d",ans);
61     return 0;
62 }

这个代码没用离散化  所以得分是悲剧的

我们注意到那个过不了的数据是907741 超出范围了 所以我们要用离散化技术把元数据处理成等价的小数据

最终正确的代码如下

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=100000;
const int maxm=5000000;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define getmid int mid=(r+l)/2

struct u
{
    int a,id;
};

u A[maxn];

bool cmp(u a,u b){
    return a.a<b.a;
}

int n,maxx[maxn*4],B[maxn],ans;

void update(int l,int r,int rt,int a,int b)
{
    if(a<=l && a>=r)
    {
        maxx[rt]=max(maxx[rt],b);
        return;
    }
    getmid;
    if(a<=mid) update(lson,a,b);
    if(a>mid) update(rson,a,b);
    maxx[rt]=max(maxx[rt],max(maxx[lrt],maxx[rrt]));
}


int query(int l,int r,int rt,int a,int b)
{
    if(a<=l && b>=r)
    {
        return maxx[rt];
    }
    getmid;
    int ans=0;
    if(a<=mid){
        ans=max(ans,query(lson,a,b));
    }
    if(b>mid){
        ans=max(ans,query(rson,a,b));
    }
    return ans;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&A[i].a);
        A[i].id=i;
    }    
    
    sort(A+1,A+1+n,cmp);
    
    int pre=A[1].a;
    int nk=1;
    B[A[1].id]=nk;
    for(int i=2;i<=n;i++)
    {
        if(pre!=A[i].a){
            nk++;
            pre=A[i].a;
        }
        B[A[i].id]=nk;
    }
    
    
    for(int i=1;i<=n;i++)
    {
        int tp=query(0,maxn,1,0,B[i]-1)+1;  //这里要注意 查询范围是0到B[i]-1 想一想为什么
        ans=max(ans,tp);
        update(0,maxn,1,B[i],tp);
    }
    
    printf("%d",ans);
    return 0;
}

 

 

posted on 2016-12-30 13:40  清老师  阅读(125)  评论(0编辑  收藏  举报