hdu 3308 LCIS(运用push_up区间合并)

本文介绍了一种解决区间最长连续子序列问题的算法实现,该算法能够支持单点更新和快速查询,适用于动态变化的数据集。通过使用树状结构存储和维护数据,实现了高效的查询与更新操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

题意:可以单点更新,找区间最长连续子序列。


#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000010
using namespace std;
int n,m,s[N];

struct Tree{
    int l,r,c;//左右边界与连续的长度
    int ln,rn;//左右边界的值
    int ls,rs,ms;//左右最大LCIS,和区间最大LCIS
}tree[4*N];

void push_up(int i){
    tree[i].ls = tree[2*i].ls;
    tree[i].rs = tree[2*i+1].rs;
    tree[i].ln = tree[2*i].ln;
    tree[i].rn = tree[2*i+1].rn;
    tree[i].ms = max(tree[2*i].ms,tree[2*i+1].ms);
    if(tree[2*i].rn<tree[2*i+1].ln){  //如果左子树的右边界值小于右子树的左边界值,要合并左子树的右边界和右子树的左边界
        if(tree[2*i].ls == tree[2*i].c)
            tree[i].ls+=tree[2*i+1].ls;
        if(tree[2*i+1].rs == tree[2*i+1].c)
            tree[i].rs+=tree[2*i].rs;
        tree[i].ms = max(tree[i].ms,tree[2*i].rs+tree[2*i+1].ls);
    }
}
void build(int t,int l,int r){
    tree[t].l=l;
    tree[t].r=r;
    tree[t].c=r-l+1;
    if(l==r){
        tree[t].ln=tree[t].rn=s[l];
        tree[t].ls=tree[t].rs=tree[t].ms=1;
        return;
    }
    int mid=(l+r)>>1;
    build(2*t,l,mid);
    build(2*t+1,mid+1,r);
    push_up(t);
}
void update(int t,int pos,int val){
    if(tree[t].l==tree[t].r){
        tree[t].ln=tree[t].rn=val;
        return;
    }
    int mid=(tree[t].l+tree[t].r)>>1;
    if(pos<=mid)
        update(2*t,pos,val);
    else
        update(2*t+1,pos,val);
    push_up(t);   //向上维护
}
int query(int t,int l,int r){
    if(l<=tree[t].l&&r>=tree[t].r)
        return tree[t].ms;
    int mid=(tree[t].l+tree[t].r)>>1,ans=0;
    if(l<=mid) ans=max(ans,query(2*t,l,r));
    if(r>mid)  ans=max(ans,query(2*t+1,l,r));
    if(tree[2*t].rn < tree[2*t+1].ln)
        ans=max(ans, min(mid-l+1,tree[2*t].rs) + min(r-mid,tree[2*t+1].ls));
    //不能超过边界啊,所以右边要小于r-mid,左边同理。
    return ans;
}
int main(){
    int t;
    char ss[3];
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&s[i]);
        build(1,1,n);
        while(m--){
            int a,b;
            scanf("%s%d%d",ss,&a,&b);
            if(ss[0]=='Q')
                printf("%d\n",query(1,a+1,b+1));
            else
                update(1,a+1,b);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值