LCIS--线段树

LCIS

题目大意:

编号为0~n-1的n个数组,

两种操作:

Q l r:查询区间[l,r]中最长连续递增子串的长度

U p x:将下标为p的点更新为x

输入描述

T(表示样例数量)

n m

n个数

m行操作

输出描述

每个查询操作输出查询结果

解题思路

线段树的单点修改,区间查询;由于是单点修改,则修改时只会将值向上传递,即只涉及pushup。 pushup操作如何合并两个子区间,可以记录下区间的左右边缘的最长增长子串(lmx,rmx)。合并时考虑边界合并即可。

区间的vmx 就是 max(左区间的vmx,右区间的vmx),如果左区间的右端和右区间的左端是连续递增的,就还要把他们两端的长度加起来,三者中最大的就是区间的vmx。

区间的lmx(rmx)就是左区间的lmx(右区间的rmx),如果整个左区间(右区间)都是递增的,那么还要加上右区间的lmx(左区间的rmx)。

runtime err或wa的debug经验:本题交了快10次了才ac,一直RE/WA。基本上写线段树没有一次是直接ac的。一般遇到过这几个原因:1.int溢出 2.忘记初始化 3.思路正确,但是某段代码出现手误(最主要) 4.思路错误,对线段树的掌握不够熟练。

代码

#include<bits/stdc++.h>
using namespace std;

int n,m;
struct node
{
    int l,r;
    int vmx;
    int lmx,rmx;
}tr[400005];
int a[100005];
void pushup(node &x,node &y,node &z)
{
    
    if(y.lmx==y.r-y.l+1&&a[y.r]<a[z.l])
    {
        x.lmx=y.lmx+z.lmx;
    }
    else x.lmx=y.lmx;
    
    if(z.rmx==z.r-z.l+1&&a[y.r]<a[z.l])
    {
        x.rmx=y.rmx+z.rmx;
    }
    else x.rmx=z.rmx;
    
    x.vmx=max(y.vmx,z.vmx);
    if(a[y.r]<a[z.l])
    {
        x.vmx=max(x.vmx,y.rmx+z.lmx);
    }
}
void pushup(int u)
{
    pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r)
{
    tr[u].l=l;
    tr[u].r=r;
    if(l==r)
    {
        tr[u].vmx=tr[u].rmx=tr[u].lmx=1;
        return ;
    }
    int mid=l+r>>1;
    build(u<<1,l,mid);build(u<<1|1,mid+1,r);
    
    pushup(u);
    
}
node query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r)return tr[u];
    
    int mid=tr[u].l+tr[u].r>>1;
    node res;
    
    if(mid>=r)res=query(u<<1,l,r),res.l=tr[u].l,res.r=tr[u].r;
    else if(mid<l)res=query(u<<1|1,l,r),res.l=tr[u].l,res.r=tr[u].r;
    else
    {
        res.l=tr[u].l;
        res.r=tr[u].r;
        auto left=query(u<<1,l,r);
        auto right=query(u<<1|1,l,r);
        pushup(res,left,right);
    }
    return res;
}
void modify(int u,int pos,int x)
{
    if(tr[u].l==tr[u].r&&tr[u].l==pos)
    {
        a[pos]=x;
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(pos<=mid)modify(u<<1,pos,x);
    else modify(u<<1|1,pos,x);
    pushup(u);
    
}
void solve()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)cin>>a[i];
    build(1,0,n-1);
    while(m--)
    {
        char op;cin>>op;
        if(op=='Q')
        {
            int l,r;
            cin>>l>>r;
            cout<<query(1,l,r).vmx<<endl;
        }
        else 
        {
            int pos,x;cin>>pos>>x;
            
            modify(1,pos,x);
        }
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
        solve();
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值