hdu 3564 线段树+dp(最大递增子序列)

来源:互联网 发布:开发一套淘宝采集软件 编辑:程序博客网 时间:2024/06/05 00:43

对于数列插空问题, 常用线段树来处理,从后往前,因为后面的数的位置是不会改变的,对于i的位置  ,如果i位置上已经有数了,那么就找i之后第一个空位,num【i】=k纪录i所放的位置, 然后就按照hdu1025做法一样了    ,

#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#define LL(x) (x<<1)#define RR(x) ((x<<1)|1)int num[100010],id[100010];int mark[4*100010];int deal(int L,int R,int point){    mark[point]=R-L+1;    if(R==L) return 0;    int mid=(L+R)/2;    deal(L,mid,LL(point));    deal(mid+1,R,RR(point));    return 0;}int find(int L,int R,int pos,int point,int k){    mark[point]--;    if(L==R)    {        num[k]=L;        return 0;    }    int mid=(L+R)/2;    if(pos<=mark[LL(point)]) find(L,mid,pos,LL(point),k);    else find(mid+1,R,pos-mark[LL(point)],RR(point),k);    return 0;}int main(){    int T,i,j,n,d=1;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(i=1;i<=n;i++)        {            scanf("%d",&id[i]);                id[i]++;        }        deal(1,n,1);        for(i=n;i>=1;i--)        {            find(1,n,id[i],1,i);        }        //for(i=1;i<=n;i++)        //printf("%d ",num[i]);        //printf("\n");        int dis[100010],len=1;        dis[1]=num[1];        printf("Case #%d:\n1\n",d++);        for(i=2;i<=n;i++)        {            if(num[i]>dis[len])             {                len++;                dis[len]=num[i];            }            else             {                int left=1,right=len;                //int flash=0;                while(left<=right)                {                    int mid=(left+right)/2;                    if(dis[mid]<num[i]) left=mid+1;                    else right=mid-1;                }                //if(flash) dis[1]=num[i];                dis[left]=num[i];            }            printf("%d\n",len);        }        printf("\n");    }    return 0;    }

0 0
原创粉丝点击