hdu3308 LCIS(线段树区间合并)

题目链接:hdu3308

/*hdu3308 LCIS 线段树区间合并
题目大意:
    求一段区间内的连续最长
思路:
    记录以区间左端点开始的LCIS,以区间右端点结尾的LCIS以及整个区间的LCIS,
区间左端点的数和区间右端点的数。
更新和建树操作都应更到叶子节点,只有叶子节点的信息时可以直接得出,然后
递归回到父节点,父节点可以根据左右孩子的信息来更新自己
*/
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int N = 200005;
struct node
{
    int lnum, rnum;//区间最左端的数和最右端的数
    int llen;//以左端点开始的连续最长
    int rlen;//以右端点结束的连续最长
    int mlen;//区间内的连续最长
}s[N<<2];
void pushup(int rt, int m)
{
    s[rt].lnum = s[rt<<1].lnum;
    s[rt].rnum = s[rt<<1|1].rnum;
    s[rt].llen = s[rt<<1].llen;
    s[rt].rlen = s[rt<<1|1].rlen;
    s[rt].mlen = max(s[rt<<1].mlen, s[rt<<1|1].mlen);
    if(s[rt<<1].rnum < s[rt<<1|1].lnum)//左儿子的右端点<右儿子的左端点
    {
        if(s[rt].llen == m - (m>>1))//左儿子表示的区间里的所有数,连续递增
            s[rt].llen += s[rt<<1|1].llen;
        if(s[rt].rlen == (m>>1))//右儿子表示的区间里的所有数,连续递增
            s[rt].rlen += s[rt<<1].rlen;
        s[rt].mlen = max(s[rt<<1].rlen + s[rt<<1|1].llen, s[rt].mlen);//左儿子的右连续长度+右儿子的左连续长度
    }
}
void build(int l, int r, int rt)
{
    s[rt].llen = s[rt].rlen = s[rt].mlen = 1;
    if(l == r)
    {
        scanf("%d",&s[rt].lnum);
        s[rt].rnum = s[rt].lnum;
        return;
    }
    int m = (l+r) >> 1;
    build(lson);
    build(rson);
    pushup(rt, r-l+1);
}
void update(int pos, int num, int l, int r, int rt)
{
    if(l == pos && pos == r)
    {
        s[rt].llen = s[rt].rlen = s[rt].mlen = 1;
        s[rt].lnum = s[rt].rnum = num;
        return;
    }
    int m = (l+r) >> 1;
    if(pos <= m) update(pos, num, lson);
    else update(pos, num, rson);
    pushup(rt, r-l+1);
}
int query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R)
    {
        return s[rt].mlen;
    }
    int m = (l+r) >> 1;
    int ans = 0;
    if(L <= m)
        ans = max(ans, query(L, R, lson));
    if(m < R)
        ans = max(ans, query(L, R, rson));
    if(s[rt<<1].rnum < s[rt<<1|1].lnum)
        ans = max(ans, min(m-L+1,s[rt<<1].rlen) + min(R-m, s[rt<<1|1].llen) );
    return ans;
}
int main()
{
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        build(1, n, 1);
        char a[2];
        int x,y;
        while(m--)
        {
            scanf("%s%d%d",a,&x,&y);
            if(a[0] == 'Q')
                printf("%d\n",query(x+1, y+1, 1, n, 1));
            if(a[0] == 'U')
                update(x+1, y, 1, n, 1);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值