LCIS

F - LCIS
Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

Given n integers. 
You have two operations: 
U A B: replace the Ath number by B. (index counting from 0) 
Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b]. 
 

Input

T in the first line, indicating the case number. 
Each case starts with two integers n , m(0<n,m<=10  5). 
The next line has n integers(0<=val<=10  5). 
The next m lines each has an operation: 
U A B(0<=A,n , 0<=B=10  5
OR 
Q A B(0<=A<=B< n). 
 

Output

For each Q, output the answer.
 

Sample Input

     
1 10 10 7 7 3 3 5 9 9 8 1 8 Q 6 6 U 3 4 Q 0 1 Q 0 5 Q 4 7 Q 3 5 Q 0 2 Q 4 6 U 6 10 Q 0 9
 

Sample Output

     
1 1 4 2 3 1 2 5

刚看完题以为跟前一题hotel一样都是区间合并,后来准备开始敲的时候发现还是跟那个题差很多,这个题需要做的是查询区间内最长的升序排列数,也就是需要比较左儿子的最右端值与右儿子的最左端值,也就是需要在结构体里面多加两个变量。还有一个需要注意的是这题是从0开始的,而我建立的树是从1开始的,所以更新和查询时的区间或点都应该加一。

#include <iostream>
#include<cstdio>
#include<algorithm>
#define lson id<<1
#define rson id<<1|1
using namespace std;
int a[100010];
struct node
{
    int le,ri,lm,rm;                  //le是区间的左端,ri是区间的右端,lm是区间内左端的数值,rm是区间内右端的数值
    int ls,rs,ms;                     //这个和hotel一样
}t[100010*4];
void pushup(int id)
{
    t[id].ls=t[lson].ls;
    t[id].rs=t[rson].rs;
    t[id].lm=t[lson].lm;
    t[id].rm=t[rson].rm;
    t[id].ms=max(t[lson].ms,t[rson].ms);                     //首先是认为父节点的最大连续值是等于左儿子和右儿子的最大连续值中较大的值
    if(t[lson].rm<t[rson].lm)                               //如果左儿子的右端数值小于右儿子的左端数值,那么父节点的左右开始以及整个区间的连续值都可能需要更新
        {
            int m=t[id].ri-t[id].le+1;
        if(t[lson].ls==m-m/2)
            t[id].ls+=t[rson].ls;
        if(t[rson].rs==m/2)
            t[id].rs+=t[lson].rs;
        t[id].ms=max(t[id].ms,t[lson].rs+t[rson].ls);
        }
}


void build(int id,int l,int r)
{
    t[id].le=l;
    t[id].ri=r;
    if(l==r) {
        t[id].lm=t[id].rm=a[l];
        t[id].ls=t[id].rs=t[id].ms=1;
        return ;
    }
    int m=(l+r)>>1;
    build(lson,l,m);
    build(rson,m+1,r);
    pushup(id);                             //本来之前是写了一段的,后来写pushup时发现两端代码长得差不多,就去掉了改为pushup
}
void update(int id,int x,int y)
{
    if(t[id].le==t[id].ri)
    {
        t[id].lm=t[id].rm=y;
        return ;
    }
    int m=(t[id].le+t[id].ri)/2;
    if(x<=m) update(lson,x,y);
    else update(rson,x,y);
    pushup(id);
}
int query(int id,int l,int r)
{
    if(l<=t[id].le&&t[id].ri<=r)
        return t[id].ms;
    int m=(t[id].le+t[id].ri)/2;
    int ret=0;
    if(l<=m) ret=max(ret,query(lson,l,r));           //先往左儿子区间查找,更新ret        
    if(r>m) ret=max(ret,query(rson,l,r));             //左儿子查完后,往右儿子区间查找,更新ret
    if(t[lson].rm<t[rson].lm)                                   //当满足能合并的条件时
        ret=max(ret,min(t[lson].rs,m-l+1)+min(t[rson].ls,r-m));                      //左儿子的右开始连续不能大于所查区间在左儿子中所占的长度,右儿子的左开始连续不能大于所查区间在右儿子中所占的长度,在把两边合并起来与re比较t取较大值
    return ret;
}
int main()
{
    int n,m,c;
    scanf("%d",&c);
    while(c--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        build(1,1,n);
        for(int i=0;i<m;i++){
        char b[2];
        int x,y;
        scanf("%s",b);
        if(b[0]=='U')
        {
            scanf("%d%d",&x,&y);
            update(1,x+1,y);                               //更新的点的位置也需要加一
        }
        else{
            scanf("%d%d",&x,&y);
            printf("%d\n",query(1,x+1,y+1));              //因为是从0开始,区间都需要加一
        }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值