HDU 3564 线段树+DP

本文介绍了一种结合线段树与最长递增子序列(LIS)算法的方法,用于解决特定类型的数值填充问题。通过记录数值位置并利用线段树进行更新,实现了对LIS的有效维护与查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值