首页 > 其他 > 详细

HDU 3564 线段树+DP

时间:2015-03-25 17:14:00      阅读:130      评论:0      收藏:0      [点我收藏+]

给出1~n的插入顺序,要求每次插入之后的LIS

对于样例: 

0:1插入到当前第0个位置后  1

0:2插入到当前第0个位置后   2 1

2:3插入到当前第2个位置后   2  1  3


线段树处理空格填数问题,然后做LIS

难点主要是如何处理LIS,因为每次填入的数字都是递增的,所以1——>n循环下去一定是递增的。

mark记录每个数字的位置,因为数值递增,所以在保证LIS足够长的情况下,位置小的取小者,最后可以得到最长的值


#include "stdio.h"
#include "string.h"
#include "algorithm"
using namespace std;

struct Data
{
    int l,r,x;
}data[400010];
int dp[100010],mark[100010],a[100010],cnt;
void build(int l,int r,int k)
{
    int mid;
    data[k].l=l;
    data[k].r=r;
    data[k].x=r-l+1;
    if (l==r) return ;
    mid=(l+r)/2;

    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
}

void updata(int x,int op,int k)
{
    if (data[k].l==data[k].r)
    {
        data[k].x=0;
        mark[op]=data[k].l;
        return ;
    }
    data[k].x--;
    if (data[k*2].x>=x) updata(x,op,k*2);
    else updata(x-data[k*2].x,op,k*2+1);
}

int two_search(int x)
{
    int l,r,mid;
    l=1; r=cnt;
    while (l<=r)
    {
        mid=(l+r)/2;
        if (dp[mid]<x) l=mid+1;
        else r=mid-1;
    }
    return l;
}

int Max(int a,int b)
{
    if (a<b) return b;
    else return a;
}

int main()
{
    int T,Case,i,n,temp;
    scanf("%d",&T);
    Case=1;
    while (T--)
    {
        scanf("%d",&n);
        for (i=1;i<=n;i++)
            scanf("%d",&a[i]);
        printf("Case #%d:\n",Case++);

        build(1,n,1);
        for (i=n;i>=1;i--)
            updata(a[i]+1,i,1);

        memset(dp,0,sizeof(dp));
        cnt=0;
        for (i=1;i<=n;i++)
        {
            temp=two_search(mark[i]);
            cnt=Max(cnt,temp);
            dp[temp]=mark[i];
            printf("%d\n",cnt);
        }
        printf("\n");
    }
    return 0;
}



HDU 3564 线段树+DP

原文:http://blog.csdn.net/u011932355/article/details/44623919

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!