hdu 3308(区间和并)

题意:

求最长上升子序列的最大长度。

两种操作:

Q 某一段区间的最长上升子序列的最大长度为多少

U: 某一点 = val

解题思路:

如果单单求最长上升子序列,我们可以通过dp,或者分治的思想来求。因为此处操作多,所以上述方法不可行。

我们在线段树的结点里增加几个域:

lsum :  表示从当前结点的最左端开始的上升子序列的长度

rsum:  表示从当前结点的最右端开始的上升子序列的长度

sum:表示当前结点上升子序列长度的最大值

所以在比较时:

同连续的区间一样 ,但要是递增的,所以左子树.rsum + 右子树.lsum

的前提条件是 左子树最右处的值要<右子树最左边的值

注意:

是递增的


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXN0 100010
#define l1(x) ((x)<<1)
#define r1(x) ((x)>>1)

struct TRnode{
    int L,R;
    int lsum,rsum,sum;
    
};
int val[MAXN0];
TRnode TR[MAXN0<<2];
int max(int aa,int bb){
    return aa>bb?aa:bb;
}
void pu(int k,int k1,int k11){
    int tmp0 = TR[k1].R - TR[k1].L + 1 ;
    if(TR[k1].lsum == tmp0){
        if(val[TR[k1].R]<val[TR[k11].L]){
            TR[k].lsum = TR[k1].lsum + TR[k11].lsum;
        }
        else {
            TR[k].lsum = TR[k1].lsum;
        }
    }
    else {
        TR[k].lsum = TR[k1].lsum;
    }
    tmp0 = TR[k11].R - TR[k11].L + 1;
    if(tmp0==TR[k11].rsum){
        if(val[TR[k1].R]<val[TR[k11].L]){
            TR[k].rsum = TR[k11].rsum + TR[k1].rsum;
        }
        else {
            TR[k].rsum = TR[k11].rsum;
        }
    }
    else {
        TR[k].rsum = TR[k11].rsum;
    }
    if(val[TR[k1].R]<val[TR[k11].L]){
        tmp0 = TR[k1].rsum + TR[k11].lsum;
    }
    else {
        tmp0 = max(TR[k1].rsum,TR[k11].lsum);
    }
    TR[k].sum = max(TR[k].rsum,TR[k].lsum);
    TR[k].sum = max(TR[k].sum,tmp0);
    TR[k].sum = max(max(TR[k1].sum,TR[k11].sum),TR[k].sum);
}
void buildTR(int L,int R,int k){
    TR[k].L = L;
    TR[k].R = R;
    if(L==R){
        TR[k].sum = TR[k].lsum = TR[k].rsum = 1;
        return;
    }
    int mid = r1(L+R);
    int k1,k11;
    k1 = l1(k);
    k11 = k1 + 1;
    buildTR(L,mid,k1);
    buildTR(mid+1,R,k11);
    pu(k,k1,k11);
}
int query(int L,int R,int k){
    if(TR[k].L==L&&TR[k].R==R){
        return TR[k].sum;
    }
    int k1,k11;
    k1 = l1(k);
    k11 = k1 + 1 ;
    int mid = r1(TR[k].L + TR[k].R);
    if(mid>=R){
        return query(L,R,k1);
    }
    else if(mid<L){
        return query(L,R,k11);
    }
    else {
        int tmp0,tmp1,tmp2,tmp3,tmp4,tmp5;
        tmp0 = query(L,mid,k1);
        tmp1 = query(mid+1,R,k11);
        tmp2 = 0;
        tmp3 = mid - L + 1;
        tmp4 = R - mid;
        tmp5 = 0;
        if(TR[k1].rsum<=tmp3){
            tmp3 = TR[k1].rsum;
        }
        if(TR[k11].lsum<=tmp4){
            tmp4 = TR[k11].lsum;
        }
        if(val[TR[k1].R]<val[TR[k11].L]){
            
            tmp2 = tmp3 + tmp4;
        }
        else {
            tmp2 = max(tmp3,tmp4);
            //tmp2 = max(TR[k1].rsum>=,TR[k11].lsum);
        }
        return max(tmp0,max(tmp1,tmp2));
    }
}
void update(int A,int B,int k){
    if(TR[k].L==TR[k].R){
        TR[k].sum =  TR[k].rsum = TR[k].lsum = 1;
        val[TR[k].L] = B;
        return;
    }
    int mid = r1(TR[k].L+TR[k].R);
    int k1,k11;
    k1 = l1(k);
    k11 = k1 + 1;
    if(mid>=A){
        update(A,B,k1);
    }
    else {
        update(A,B,k11);
    }
    pu(k,k1,k11);
}
int main(){
    int n,m,A,B,ans;
    char w[1];
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%d",&val[i]);
        }
        buildTR(1, n, 1);
        while(m--){
            scanf("%s",w);
            if(w[0]=='Q'){
                scanf("%d%d",&A,&B);
                ++A;
                ++B;
                int ans =  query(A,B,1);
                printf("%d\n",ans);
            }
            else {
                scanf("%d%d",&A,&B);
                ++A;
                update(A,B,1);
            }
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值