HDU 3308 LCIS 线段树 区间更新

  题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3308

  题目描述: 有两种操作, U x y  , 第xth赋值为y 。Q x y , 查询区间x-y的最长连续上升子序列的长度L

  解题思路: 对于线段树不好的我依然好难.....有太多细节需要注意了....但是这是一道很好的题, 一段区间的L可能从三个地方来, 一种是中间, 一种是以左起点为开头的, 一种是以右起点结尾的, 这样查询的时候就要注意了: 如果两段的中间值是a[m] < a[m+1] 我们就要从这三段中选出一个最大的, 否则就只从前两段中选出最大的. .....然后向上更新的时候要注意: 如果左区间是一个整个的LCIS, 那我们就应该将左区间更新为左区间加上左儿子的右区间, 右区间同理, 我解释的比较拗口......其实这是很巧的 , 我们可以从第一步将数画在纸上构造一遍就会很清楚.....最后BUG当然是不能少的啦........我啥都缺, 就是不缺BUG

  代码: 

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iterator>
#include <cmath>
#include <algorithm>
#include <stack>
#include <deque>
#include <map>
#include <set>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define mem0(a) memset(a,0,sizeof(a))
#define sca(x) scanf("%d",&x)
#define de printf("=======\n")
typedef long long ll;
using namespace std;

int n, mm, t;
const int maxn = 1e5+10;
int no[maxn<<2], ls[maxn<<2], rs[maxn<<2];
int a[maxn];
int x, y;

inline void pushUp( int l, int r, int rt ) {
    int m = (l+r) >> 1;
    ls[rt] = ls[rt<<1];
    rs[rt] = rs[rt<<1|1];
    no[rt] = max( no[rt<<1], no[rt<<1|1] );
    if( a[m] < a[m+1] ) {
        if(ls[rt] == m-l+1) ls[rt] += ls[rt<<1|1];
        if(rs[rt] == r-m) rs[rt] += rs[rt<<1];
        no[rt] = max( no[rt], ls[rt<<1|1]+rs[rt<<1] );
    }
}

void build(int l, int r, int rt) {
    if( l == r ) {
        no[rt] = ls[rt] = rs[rt] = 1;
        return;
    }
    int m = (l+r) >> 1;
    build( lson );
    build( rson );
    pushUp(l, r, rt);
}

void update(int l, int r, int rt) {
    if( l == r ) return;
    int m = (l+r) >> 1;
    if( x <= m ) update(lson);
    else update(rson);
    pushUp(l, r, rt);
}

int query(int l, int r, int rt) {
//    cout << l << " " << r << endl; cout << "rt: " << rt << endl;
    if( x <= l && r <= y ) return no[rt];
    int m = (l + r) >> 1;
    if( y <= m ) return query(lson);
//    cout << "**" << endl;
    if( x > m ) return query(rson);

    int t1 = query(lson);
    int t2 = query(rson);
    int ans = max( t1, t2 );
    if( a[m] < a[m+1] ) {
//        ans = max( ans, ls[rt<<1|1]+rs[rt<<1] );
        ans=max(ans,(min(ls[rt<<1|1],y-m)+min(rs[rt<<1],m+1-x)));
    }
    return ans;
}


int main() {
    sca(t);
    while( t-- ) {
        scanf( "%d%d", &n, &mm );
        for( int i = 1; i <= n; i++ ) {
            sca(a[i]);
        }
        build(1, n, 1);
        char op[5];
        while( mm-- ) {
            scanf( "%s%d%d", op, &x, &y );
            ++x;
            if( op[0] == 'U' ) {
                a[x] = y;
                update(1, n, 1);
            }
            else {
                ++y;
                printf( "%d\n", query(1, n, 1) );
            }
        }
    }
    return 0;
}
View Code

  思考: 线段树是个大坑啊....自己挖的坑自己填吧.......看看剑指offer啥的吧....下午又是水课

转载于:https://www.cnblogs.com/FriskyPuppy/p/7472987.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值