hdu3308




给定10^5个数,区间查询严格上升的最长连续序列长度,点更新某个数.

每个区间记录包括左边最长,右边最长,全局最长即可...


code:

#include <cstdio>
#include <cstring>
#include <cassert>
#include <vector>
#include <algorithm>
#include <iostream>


using namespace std;


#define N 100050
#define LL L, m, c<<1
#define RR m+1, R, c<<1|1
#define max(a, b) a>b?a:b


struct node{int l, r, a; };
int dt[N], lt[N<<2], rt[N<<2], at[N<<2];
// data, left, right, all


void pushUp(int L, int R, int c){
    int m=(L+R)>>1;


    lt[c]=lt[c<<1]; rt[c]=rt[c<<1|1];
    at[c]=max(at[c<<1], at[c<<1|1]);
    
    if(dt[m]<dt[m+1]){
        if(lt[c<<1]==m-L+1) lt[c]+=lt[c<<1|1];
        if(rt[c<<1|1]==R-m) rt[c]+=rt[c<<1];
        at[c]=max(at[c], rt[c<<1]+lt[c<<1|1]);
    }
}


// seg build
void build(int L, int R, int c)
{
    if(L==R) {
        scanf("%d", &dt[L]);
        lt[c]=rt[c]=at[c]=1;
        return; 
    }
    
    int m=(L+R)>>1;
    build(LL);    
    build(RR);    


    pushUp(L, R, c);
}


// point update
void update(int l, int v, int L, int R, int c)
{
    if(l<=L && R<=l){ 
        dt[l]=v;    return; 
    }
    
    int m=(L+R)>>1;
    if(l<=m) update(l, v, LL);
    else update(l, v, RR);


    pushUp(L, R, c);
}


// seg ques
node ques(int l, int r, int L, int R, int c)
{
    node lv, rv, av;


    av.a=av.l=av.r=1;


    if(l==L && R==r) {
        av.a=at[c];
        av.l=lt[c];
        av.r=rt[c];
        return av;
    }


    int m=(L+R)>>1;
    
    if(r<=m) return ques(l, r, LL);
    else if(l>m) return ques(l, r, RR);
    else {
        lv=ques(l, m, LL);
        rv=ques(m+1, r, RR);
        
        av.l=lv.l; av.r=rv.r;
        av.a=max(lv.a, rv.a);
        if(dt[m]<dt[m+1]) {
            if(lv.l==m-l+1) av.l+=rv.l;
            if(rv.r==r-m) av.r+=lv.r;
            av.a=max(av.a, lv.r+rv.l);
        }    
        
        return av;
    }
}


int main()
{
    int t, n, q;
    
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &q);
        build(1, n, 1);
        char ch[2];
        int a, b;
        while(q--){
            scanf("%s%d%d", ch, &a, &b);
            if(*ch=='Q')
                printf("%d\n", ques(a+1, b+1, 1, n, 1).a);
            else if(*ch=='U') update(a+1, b, 1, n, 1);
            else assert(0>1);
        }
    }


    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值