POJ 1631 nlogn求LIS

方法一: 二分

我们可以知道 最长上升子序列的 最后一个数的值是随序列的长度而递增的 (呃呃呃 意会意会)
然后我们就可以二分找值了(并更新)

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,cases,a[100050],f[100050],vis[100050];
int search(int x){
    int l=0,r=n,ans=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(vis[mid]<=x)l=mid+1,ans=mid;
        else r=mid-1;
    }
    return ans;
}
int main()
{
    scanf("%d",&cases);
    while(cases--){
        memset(f,0,sizeof(f));
        memset(vis,0x3f,sizeof(vis)),vis[0]=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++){
            f[i]=search(a[i])+1;
            vis[f[i]]=min(vis[f[i]],a[i]);
        }
        for(int i=1;i<n;i++)f[n]=max(f[n],f[i]);
        printf("%d\n",f[n]);
    }
}

方法二:
线段树 (按照权值建) 查询前一段中的最大值。。并插入当前的值,,

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,cases,a[100050],f[100050],xx,tree[666666];
void insert(int l,int r,int pos){
    if(l==r){tree[pos]=f[xx];return;}
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<a[xx])insert(mid+1,r,rson);
    else insert(l,mid,lson);
    tree[pos]=max(tree[lson],tree[rson]);
}
int query(int l,int r,int pos){
    if(r<=a[xx])return tree[pos];
    int mid=(l+r)>>1;
    if(mid<a[xx])return max(query(l,mid,pos<<1),query(mid+1,r,pos<<1|1));
    else return query(l,mid,pos<<1);
}
int main(){
    scanf("%d",&cases);
    while(cases--){
        memset(tree,0,sizeof(tree));
        memset(f,0,sizeof(f));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(xx=1;xx<=n;xx++){
            f[xx]=query(1,n,1)+1;
            insert(1,n,1);
        }
        for(int i=1;i<n;i++)f[n]=max(f[n],f[i]);
        printf("%d\n",f[n]);
    }
}

这里写图片描述

posted @ 2016-09-25 14:34  SiriusRen  阅读(193)  评论(0编辑  收藏  举报