HDOJ 3308 LCIS(线段树区间合并与查询)

题意:

给定n个数,可以对某一个数进行更新操作,以及对于某一个区间进行“最长连续上升子序列”查询。

思路:

和上一题hotel类似,只不过减少了一个PushDown的操作。多了对于数组中元素的判断,要细心体会。

 

#include <cstdio>

#include <algorithm>

using namespace std;



#define lhs l, m, rt << 1

#define rhs m + 1, r, rt << 1 | 1



const int maxn = 100010;

int sum[maxn << 2], lsum[maxn << 2], rsum[maxn << 2];

int arr[maxn];



void PushUp(int l, int r, int rt)

{

    lsum[rt] = lsum[rt << 1];

    rsum[rt] = rsum[rt << 1 | 1];



    int m = (l + r) >> 1;

    sum[rt] = max(sum[rt << 1], sum[rt << 1 | 1]);



    if (arr[m] < arr[m + 1])

    {

        if (lsum[rt] == m - l + 1)

            lsum[rt] += lsum[rt << 1 | 1];

        if (rsum[rt] == r - m)

            rsum[rt] += rsum[rt << 1];

        sum[rt] = max(sum[rt], rsum[rt << 1] + lsum[rt << 1 | 1]);

    }

}



void Build(int l, int r, int rt)

{

    if (l == r)

    {

        sum[rt] = 1;

        lsum[rt] = rsum[rt] = 1;

        return ;

    }

    int m = (l + r) >> 1;

    Build(lhs);  Build(rhs);

    PushUp(l, r, rt);

}



void Update(int p, int value, int l, int r, int rt)

{

    if (l == r)

    {

        arr[p] = value;

        return ;

    }

    int m = (l + r) >> 1;

    if (p <= m)

        Update(p, value, lhs);

    else

        Update(p, value, rhs);

    PushUp(l, r, rt);

}



int Query(int beg, int end, int l, int r, int rt)

{

    if (beg <= l && r <= end)

        return sum[rt];



    int m = (l + r) >> 1;

    int ret = 0;



    if (beg <= m)

        ret = max(ret, Query(beg, end, lhs));

    if (end > m)

        ret = max(ret, Query(beg, end, rhs));



    if (arr[m] < arr[m + 1])

        if (beg <= m && m < end)

            ret = max(ret, min(m - beg + 1, rsum[rt << 1]) + min(end - m, lsum[rt << 1 | 1]));



    return ret;

}



int main()

{

    int cases;

    scanf("%d", &cases);

    while (cases--)

    {

        int n, m;

        scanf("%d %d", &n, &m);



        for (int i = 0; i < n; ++i)

            scanf("%d", &arr[i]);



        Build(0, n - 1, 1);



        for (int i = 0; i < m; ++i)

        {

            char op[4];

            int a, b;

            scanf("%s %d %d", op, &a, &b);



            if (op[0] == 'U')

                Update(a, b, 0, n - 1, 1);

            else if (op[0] == 'Q')

                printf("%d\n", Query(a, b, 0, n - 1, 1));

        } 

    }

    return 0;

}

你可能感兴趣的:(线段树)