hdu3564 Another LIS

Problem Description

There is a sequence firstly empty. We begin to add number from 1 to N to the sequence, and every time we just add a single number to the sequence at a specific position. Now, we want to know length of the LIS (Longest Increasing Subsequence)
after every time‘s add.

Input

An integer T (T <= 10), indicating there are T test cases.

For every test case, an integer N (1 <= N <= 100000) comes first, then there are N numbers, the k-th number Xk means that we add number k at position Xk (0 <= Xk <= k-1).See hint for more details.

Output

For the k-th test case, first output "Case #k:" in a separate line, then followed N lines indicating the answer. Output a blank line after every test case.

Sample Input

1
3
0 0 2

Sample Output

Case #1:
1
1
2

Hint

In the sample, we add three numbers to the sequence, and form three sequences.
a. 1
b. 2 1
c. 2 1 3

这题看了别人的题解,最后看懂了。题意是从1~n,一次插入位置,然后每插入一个数求出它的最长递增子序列(不连续)。可以用线段树先求出每个数所在的位置,可以从后往前,因为每次最后一个数的位置一定是固定的。然后就是二分法的lis了,这里如果继续用线段树求lis的话会超时的。

这里二分的lis之前一直看不懂,其实因为输入的数是一次增大的,所以每次只要记录这个数的位置,然后二分找到最接近但大于当前数的位置,然后替换掉找到的数。

这题我对二分又有了新的认识,二分模板不是固定的,而是根据题目意思决定最后返回的值是l还是r.
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
#define maxn 100005
int a[maxn],ans[maxn],dp[maxn];
struct node{
    int l,r,n;
}b[4*maxn];

void build(int l,int r,int i)
{
    int mid;
    b[i].l=l;b[i].r=r;b[i].n=r-l+1;
    if(l==r)return;
    mid=(l+r)/2;
    build(l,mid,i*2);
    build(mid+1,r,i*2+1);
}

void update(int index,int m,int i)
{
    int mid;
    if(b[i].l==b[i].r){
        b[i].n=0;ans[m]=b[i].l;return;
    }
    if(b[i*2].n>=index) update(index,m,i*2);
    else update(index-b[i*2].n,m,i*2+1);
    b[i].n=b[i*2].n+b[i*2+1].n;
}

int find(int l,int r,int x)
{
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        if(dp[mid]>x){
            r=mid-1;
        }
        else l=mid+1;
    }
    return r+1; //这里也可以是l,可以草稿纸上画一下
}

int main()
{
    int n,m,i,j,h,T,k,len; //len表示最长递增子序列
    scanf("%d",&T);
    for(h=1;h<=T;h++)
    {
        printf("Case #%d:\n",h);
        scanf("%d",&n);
        for(i=1;i<=n;i++){scanf("%d",&a[i]);dp[i]=0;}
        build(1,n,1);
        for(i=n;i>=1;i--){
            update(a[i]+1,i,1);
        }
        len=0;
        for(i=1;i<=n;i++){
            if(len==0){
                dp[++len]=ans[1];  //ans[]表示i所在的位置
                printf("%d\n",len);
                continue;
            }
            k=find(1,len,ans[i]);
            len=max(len,k); //不管这n个数排列顺序怎样,每一次的最长递增子序列一定是递增的,可以画一下。
            dp[k]=ans[i];  //dp[k]表示最长递增序列中的第k个数,用到了单调队列的思想
            printf("%d\n",len);
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-09-21 01:41:47

hdu3564 Another LIS的相关文章

HDU3564 Another LIS 线段树

Another LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1419    Accepted Submission(s): 521 Problem Description There is a sequence firstly empty. We begin to add number from 1 to N to the

hdu 3564 Another LIS splay

题意:依次插入i到pos[i],查询插入后当前LIS. 思路:splay.因为插入的数是升序的,那么对于i,只要知道pos[i]之前的最大LIS---x,那么以i结尾的最大LIS=x+1.那么只要在splay 中,只要维护一个当前区间最大的LIS,插入的时候,把第pos-1位的点旋到根root,把pos位的点旋到根的右结点R(root),新插入的 点插在L(R(root))即可,结点的值max(L(root)->Max,root->val)+1.注意push_up就可以了.详见代码: /***

小明系列问题――小明序列(LIS)

小明系列问题――小明序列 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4521 Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找去都是自己早已研究过的序列.小明想既然找不到,那就自己来发明一个新的序列问题吧!

hdu4521 小明系列问题——小明序列(LIS变种 (线段树+单点更新解法))

链接: huangjing 题目:中文题目 思路: 这个题目如果去掉那个距离大于d的条件,那么必然是一个普通的LIS,但是加上那个条件后就变得复杂了.用dp的解法没有看懂,我用的线段树的解法...就是采用延迟更新的做法,用为距离要大于d啊,所以我们在循环到第i的时候,就对(i-d-1)这个点进行更新,因为如果在(i-d-1)这个点更新了,会对后面的造成影响,然后线段树的tree[]数组存的是以i结尾的最长lis,那么每次询问的时候就找最大的tree[]就可以了... 代码: 小明系列问题--小明

RQNOJ 201 奥运大包围:LIS + 拼链成环

题目链接:https://www.rqnoj.cn/problem/201 题意: 开始时n(n<=1000)个人手拉手围成一个圈. 后来这些人中的一些按顺序向里面出圈形成一个新圈.从而使原圈形成一个从高到低,最低与最高连接的圈. 新圈重复相同的操作,直到没有人要出圈为止. 问最少要形成多少个这样的圈. 题解: (1)拼链成环: 对于一个环,可以用两条由环拆开的链拼在一起表示. 例如:有一个环为"1,2,3,4"(1和4连在一起),则可以表示为"1,2,3,4,1,2,

Gym 101246H ``North-East&#39;&#39;(LIS)

http://codeforces.com/gym/101246/problem/H 题意: 给出n个点的坐标,现在有一个乐队,他可以从任一点出发,但是只能往右上方走(包括右方和上方),要经过尽量多的点.输出它可能经过的点和一定会经过的点. 思路: 分析一下第一个案例,在坐标图上画出来,可以发现,他最多可以经过4个点,有两种方法可以走. 观察一下,就可以发现这道题目就是要我们求一个LIS. 首先,对输入数据排一下顺序,x小的排前,相等时则将y大的优先排前面. 用二分法求LIS,这样在d数组中就可

[SDOI2014]LIS

题目描述 给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci.请删除若干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案. 如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种. 输入输出格式 输入格式: 输入包含多组数据. 输入的第一行包含整数T,表示数据组数.接下来4*T行描述每组数据. 每组数据的第一行包含一个整数N,表示A的项数,接下来三行,每行N个整数A1..An,B1.,Bn,C1..Cn,满足1 < =Ai,Bi,Ci < =10^

洛谷U4727小L的二叉树[树 LIS]

题目背景 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣. 所以,小L当时卡在了二叉树. 题目描述 在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key[p]>key[lch]:若其存在右孩子rch,则k

hdu 1087(LIS变形)

Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 31458    Accepted Submission(s): 14128 Problem Description Nowadays, a kind of chess game called “Super Jumping!