UVALive_4976

    这个题目可以先预处理出每个点向左走一共有多少个连续下降的元素,以及向右走一共有多少个连续上升的元素,处理出这两个东西后思路基本就有了。

    接下来用线段树也可以做,或者可以借鉴O(NlogN)求解最长上升子序列的方法的思想来做,但后者效率更高一些。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXD 200010
int N, a[MAXD], s[MAXD], R[MAXD], top;
void init()
{
    int i;
    scanf("%d", &N);
    for(i = 1; i <= N; i ++) scanf("%d", &a[i]);
    for(R[N] = 1, i = N - 1; i >= 1; i --) R[i] = a[i] < a[i + 1] ? R[i + 1] + 1 : 1;
}
int BS(int h)
{
    int mid, min = 0, max = top + 1;
    for(;;)
    {
        mid = min + max >> 1;
        if(mid == min) break;
        if(s[mid] < h) min = mid;
        else max = mid;
    }
    return mid;
}
void solve()
{
    int i, k, x = 1, ans = 1;
    top = 0, s[++ top] = a[1];
    for(i = 2; i <= N; i ++)
    {
        ans = std::max(ans, BS(a[i]) + R[i]);
        a[i] > a[i - 1] ? ++ x : x = 1;
        if(x > top) s[++ top] = a[i];
        else s[x] = std::min(s[x], a[i]);
    }
    printf("%d\n", ans);
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t --)
    {
        init();
        solve();
    }
    return 0;
}
posted on 2012-08-24 21:30  Staginner  阅读(533)  评论(1编辑  收藏  举报