【题意】题意很简单,就是给了两个操作,一个是U A B,代表将第A个元素用B代替,还有一个是Q A B,查询[A,B]区间里面的最长上升子序列,即LCIS。(ps:这里需要注意的是LCIS为严格的上升子序列,比如5,5,5,这个序列的LCIS为1,不是为3)

【解题思路】和Hotel类似,在线段树的节点里维护三个信息,一个是节点左边的最长上升子序列,节点右边的最长上升子序列,以及跨越节点左右两边的最长上升子序列。

【具体实现】由于这里是单点更新,顾而不用延迟标记,因此这个题比HOTEL还简单一下,只需要仔细考虑一下Push_Up就可以了。那么Push_Up怎么做呢?

void Push_Up(int l,int r,int rt)
{
    lnum[rt] = lnum[rt<<1];
    rnum[rt] = rnum[rt<<1|1];
    mnum[rt] = max(mnum[rt<<1],mnum[rt<<1|1]);
    int m = (l+r)>>1;
    if(val[m]<val[m+1])
    {
        if(lnum[rt]==m-l+1) lnum[rt]+=lnum[rt<<1|1];
        if(rnum[rt]==r-m)   rnum[rt]+=rnum[rt<<1];
        mnum[rt] = max(mnum[rt],rnum[rt<<1]+lnum[rt<<1|1]);
    }
}

用子节点的信息去更新父节点的信息就可以了,当出现了跨越某个节点左右区间的情况则需要特殊的更新一下,具体实现看代码。

【AC代码】

//Created Author :just_sort
//Created Time   :2016/3/2 19:13
//Created File   :LCIS
/***************************/
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 100010;
int getInt(int &x)
{
    return scanf("%d",&x);
}
int val[maxn];
int lnum[maxn<<2],rnum[maxn<<2],mnum[maxn<<2];
void Push_Up(int l,int r,int rt)
{
    lnum[rt] = lnum[rt<<1];
    rnum[rt] = rnum[rt<<1|1];
    mnum[rt] = max(mnum[rt<<1],mnum[rt<<1|1]);
    int m = (l+r)>>1;
    if(val[m]<val[m+1])
    {
        if(lnum[rt]==m-l+1) lnum[rt]+=lnum[rt<<1|1];
        if(rnum[rt]==r-m)   rnum[rt]+=rnum[rt<<1];
        mnum[rt] = max(mnum[rt],rnum[rt<<1]+lnum[rt<<1|1]);
    }
}
void Build(int l,int r,int rt)
{
    if(l==r)
    {
        lnum[rt]=rnum[rt]=mnum[rt]=1;
        return ;
    }
    int m = (l+r)>>1;
    Build(lson);
    Build(rson);
    Push_Up(l,r,rt);
}
void Update(int p,int sc,int l,int r,int rt)
{
   if(l==r){val[l]=sc; return;}
   int m = (l+r)>>1;
   if(p<=m)  Update(p,sc,lson);
   else      Update(p,sc,rson);
   Push_Up(l,r,rt);
}
int query_ans(int L,int R,int l,int r,int rt)
{
    if(L==l&&R==r)return mnum[rt];
    int m = (l+r)>>1;
    if(R<=m) return query_ans(L,R,lson);
    if(L>m)  return query_ans(L,R,rson);
    else{
        //a为在lson区间里查到的[l,m]的LCS
        //b为在rson区间里查到的[m+1,r]的LCS
        //c为跨越左右儿子区间[L,R]上的LCS
        int a = query_ans(L,m,lson);
        int b = query_ans(m+1,R,rson);
        int c = 0;
        if(val[m]<val[m+1]){
            c+=min(rnum[rt<<1],m-L+1);
            c+=min(lnum[rt<<1|1],R-m);
        }
        return max(a,max(b,c));
    }
}
int main()
{
    int n,m,tt;
    getInt(tt);
    while(tt--)
    {
       getInt(n);
       getInt(m);
       for(int i=0;i<n;i++)getInt(val[i]);
       Build(0,n-1,1);
       char op[2];
       int a,b;
       while(m--)
       {
           scanf("%s %d %d",op,&a,&b);
           if(op[0]=='U')
           {
               Update(a,b,0,n-1,1);
           }
           else
           {
               printf("%d\n",query_ans(a,b,0,n-1,1));
           }
       }
    }
    return 0;
}