HDU3564Another LIS(线段树,LIS升级)

Another LIS

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 1211    Accepted Submission(s): 424

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


 

Author

standy

Source

2010 ACM-ICPC Multi-University Training
Contest(13)——Host by UESTC

解题:先求出这个序列+排序+LIS。

#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define N 100100
typedef struct nnn
{
    int id,i;
}point;
int tree[3*N];
point oder[N];
void bulide1(int l,int r,int k)
{
    tree[k]=r-l+1;
    if(l==r)return ;
    bulide1(l,(l+r)/2,k*2);
    bulide1((l+r)/2+1,r,k*2+1);
}
void set_tree1(int l,int r,int k,int id,int i)
{
    int m=(l+r)/2;
    tree[k]--;
    if(l==r)
    {
        oder[l].id=l; oder[l].i=i; return ;
    }
    if(tree[k*2]>=id)set_tree1(l,m,k*2,id,i);
    else set_tree1(m+1,r,k*2+1,id-tree[k*2],i);
}

bool cmp(point a,point b){return a.i<b.i;}
void bulide2(int l,int r,int k)
{
    tree[k]=0;
    if(l==r)return ;
    bulide2(l,(l+r)/2,k*2);
    bulide2((l+r)/2+1,r,k*2+1);
}
void set_tree2(int l,int r,int k,int id,int lis)
{
    int m=(l+r)/2;
    if(l==r)
    {
       if(tree[k]<lis) tree[k]=lis; return ;
    }
    if(id<=m)set_tree2(l,m,k*2,id,lis);
    else set_tree2(m+1,r,k*2+1,id,lis);

    if(tree[k*2]>tree[k*2+1])
        tree[k]=tree[k*2];
    else tree[k]=tree[k*2+1];
}
int query2(int l,int r,int k,int id)
{
    int m=(l+r)/2;
    if(l==r)return 0;
    int max=0;
    if(m>=id)
       max=query2(l,m,k*2,id);
    else
    {
        max=query2(m+1,r,k*2+1,id);
        if(max<tree[k*2]) max=tree[k*2];//左边的数一定比当前数小,因为排了个序从小到大排
    }
    return max;
}
int main()
{
    int a[N+5],LIS[N+5],m,n;
    scanf("%d",&m);
    for(int j=1;j<=m;j++)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]); a[i]++;
        }

        bulide1(1,n,1);
        for(int i=n;i>0;i--)
            set_tree1(1,n,1,a[i],i);

        sort(oder+1,oder+n+1,cmp);
        bulide2(1,n,1);
        for(int i=1;i<=n;i++)
        {
            int lis=1+query2(1,n,1,oder[i].id);
            set_tree2(1,n,1,oder[i].id,lis);
            LIS[i]=tree[1];
        }
        printf("Case #%d:\n",j);
        for(int i=1;i<=n;i++)
            printf("%d\n",LIS[i]);

        printf("\n");
    }
}
时间: 2024-10-07 20:46:26

HDU3564Another LIS(线段树,LIS升级)的相关文章

Hdu 3564 Another LIS 线段树+LIS

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

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

Codeforces 486E LIS of Sequence(线段树+LIS)

题目链接:Codeforces 486E LIS of Sequence 题目大意:给定一个数组,现在要确定每个位置上的数属于哪一种类型. 解题思路:先求出每个位置选的情况下的最长LIS,因为开始的想法,所以求LIS直接用线段树写了,没有改,可以用 log(n)的算法直接求也是可以的.然后在从后向前做一次类似LIS,每次判断A[i]是否小于f[dp[i]+1],这样就可以确定该位 置是否属于LIS序列.然后为第三类的则说明dp[i] = k的只有一个满足. #include <cstdio>

D. Babaei and Birthday Cake---cf629D(LIS线段树优化)

题目链接:http://codeforces.com/problemset/problem/629/D 题意就是现有n个蛋糕,蛋糕的形状是圆柱体,每个蛋糕的体积就是圆柱体的体积,每个蛋糕的编号是1---n,可以把蛋糕 i 放到蛋糕 j 上面,前提是 j<i 并且 Vj<Vi;最后求最大的体积是多少: 实质就是求上升子序列的最大和,但是由于n的范围是10w所以不能用n^2的复杂度,所以可以用线段树进行优化,时间复杂度变为nlogn: #include <iostream> #incl

D - Lis on Circle Gym - 102441D (LIS + 线段树)

There are nn people at the round gaming table. Each of them has a set of cards. Every card contains some number xx. Players make turns consecutively, one after another, starting from the player number 1. A player in his turn can either skip his turn

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

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

线段树求LIS并统计最长子序列个数

以下面的题目为例(题目和代码在最后面),给定一个数列(长度最大为10000),求出最长的先增后减子序列长度及个数.做法是先求出以每一个位置结尾的最长单增子序列长度以及以该位置开头的最长单减子序列长度,然后遍历所有位置找出最大先增后减子序列长度. 以最长单增序列(LIS)为例,由于不仅需要整个序列LIS的长度,还要保存以每个位置为结尾位置的LIS长度.记以a[i]结尾的LIS长度为dp[i],则 dp[i] = max{dp[j] | a[j] < a[i]} + 1 这就是一个RMQ问题,涉及单

HDOJ 题目3564 Another LIS(线段树单点更新,LIS)

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

hdu 4521 小明系列问题——小明序列(线段树+DP或扩展成经典的LIS)

小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1553    Accepted Submission(s): 457 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,但是也就由于这样,小明差点儿已经玩遍各种序列问题了.可怜的小明苦苦地在各大站点上寻找着新的序列问题,但是找来