HDU 3308 LCIS 线段树 区间合并 入门题

题意:
给出一个长度为N(N <= 100000)的数列,然后是两种操作:
U A B: 将第A个数替换为B (下标从零开始)
Q A B: 输出区间[A, B]的最长连续递增子序列
询问的次数m <= 100000。

类型:区间合并

 

这题跟POJ hotel差不多,这题应该比hotel简单一些,因为 update是单点更新,所以每次更新数据都是更新到低的,所以不用写pushdown函数,

pushup里面比hotel多了一个判断,即num[m] < num[m]时左右儿子的数据才能合并,否则不合并,其它跟hotel无差。

 

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

#define maxn 100004
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define mid int m = (l + r)>>1

int num[maxn];
int lsum[maxn<<2], rsum[maxn<<2], msum[maxn<<2];
int n, m;

void pushup(int l, int r, int rt)
{
    lsum[rt] = lsum[rt<<1];
    rsum[rt] = rsum[rt<<1|1];
    mid;
    msum[rt] = max( msum[rt<<1], msum[rt<<1|1]);
    if(num[m] < num[m+1])
    {
        if(lsum[rt] == m - l + 1) lsum[rt] += lsum[rt<<1|1];
        if(rsum[rt] == r - m) rsum[rt] += rsum[rt<<1];
        msum[rt] = max( msum[rt], rsum[rt<<1] + lsum[rt<<1|1] );
    }
}

void build(int l, int r, int rt)
{
    if(l == r) 
    { lsum[rt] = rsum[rt] = msum[rt] = 1; return; }
    mid;
    build(lson);
    build(rson);
    pushup(l, r, rt);
}

void update(int p, int v, int l, int r, int rt)
{
    if(l == r)
    { num[p] = v; return; }
    mid;
    if(p <= m) update(p, v, lson);
    else update(p, v, rson);
    pushup(l, r, rt);
}

int query(int a, int b, int l, int r, int rt)
{
    if(a <= l && r <= b)
        return msum[rt];
    mid;
    int ret = 0;
    if( a <= m ) ret = max( ret, query(a, b, lson) );
    if( b >  m ) ret = max( ret, query(a, b, rson) );
    if(num[m] < num[m+1])
    //注意:取最大值时要保证是在给定的区间[a,b]里面 
        ret = max( ret, min( m - a + 1, rsum[rt<<1]) + min(b - m, lsum[rt<<1|1]) );
    return ret;
}

char op[3];

int main()
{
    int cas, i, j;
    int a, b;
    scanf("%d", &cas);
    while( cas-- )
    {
        scanf("%d%d", &n, &m);
        for(i = 1; i <= n; i++)
            scanf("%d", &num[i]);
        build(1, n, 1);
        while( m-- )
        {
            scanf("%s%d%d", op, &a, &b);
            if(op[0] == 'Q')
                printf("%d\n", query(a+1, b+1, 1, n, 1) );//注意题目中给的位置是从0开始的 
            else 
                update(a+1, b, 1, n, 1);
        }
    }
    return 0;
}

 

posted @ 2012-08-24 15:58  To be an ACMan  Views(399)  Comments(0)    收藏  举报