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

对于数列插空问题, 常用线段树来处理,从后往前,因为后面的数的位置是不会改变的,对于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;
}
时间: 2024-09-30 06:18:48

hdu 3564 线段树+dp(最大递增子序列)的相关文章

hdu 4747 线段树/DP

先是线段树 可以知道mex(i,i),mex(i,i+1)到mex(i,n)是递增的. 首先很容易求得mex(1,1),mex(1,2)......mex(1,n) 因为上述n个数是递增的. 然后使用线段树维护,需要不断删除前面的数. 比如删掉第一个数a[1]. 那么在下一个a[1]出现前的 大于a[1]的mex值都要变成a[1] 因为是单调递增的,所以找到第一个 mex > a[1]的位置,到下一个a[1]出现位置,这个区间的值变成a[1]. 然后需要线段树实现区间修改和区间求和 #inclu

HDU 3607 线段树+DP+离散化

题意:从左往右跳箱子,每个箱子有金币数量,只能从矮处向高处跳,求最大可获得金币数,数据规模1<=n<=1e5. 显然是一个dp的问题,不难得出dp[ i ] = max(dp[j] )+val [ i ] ,j < i ; 第一眼会想到o(n^2)的算法,显然会超时,这个时候就需要用线段树维护最大值,将复杂度降低到o(nlogn) 首先离散化处理,将高度从小到大排序,并使用unique函数去重,之后每个高度就可以映射为它的下标pos,然后用线段树维护每个下标对应的最优解bestans [

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

[HDU 6447][YJJ&#39;s Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]

链接: http://acm.hdu.edu.cn/showproblem.php?pid=6447 题意: 左上角(0,0),右下角(10^9,10^9)的网格,其中有n(1<=n<=10^5)个方格内有权值. 一次只能沿右,下,右下三个方向走一个格子,只有沿右下方向走到格子里才可以获得权值. 问从(0,0)到(10^9,10^9)的路径最大权值是多少. 思路: 网格路径权值问题,第一感考虑DP,x从上往下,y从左往右刷表,状态转移方程为dp[i][j]=max(dp[i-1][j],dp[

hdu 3308 线段树单点更新 区间合并

http://acm.hdu.edu.cn/showproblem.php?pid=3308 学到两点: 1.以区间端点为开始/结束的最长......似乎在Dp也常用这种思想 2.分类的时候,明确标准逐层分类,思维格式: 条件一成立: { 条件二成立: { } else { } } else { 条件二成立: { } else { } } 上面的这种方式很清晰,如果直接想到那种情况iif(条件一 &条件二)就写,很容易出错而且把自己搞乱,或者情况不全,,,我就因为这WA了几次 3.WA了之后 ,

HDU 3308 线段树(区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3896    Accepted Submission(s): 1766 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

ZOJ3632 线段树+DP

买西瓜吃,每个西瓜有两个参数,一个是p代表价格,一个是t代表能吃几天,要求n天每天都能吃西瓜,而且如果你今天买了,以前买的还没吃完 那么都得扔了,求最小花费,还真想不到用线段树+DP,最后看了一下别人的标题,想了一下,DP方程挺好推的,线段树也只是单点查询, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #inclu