dreamxr
精诚所至,金石为开!

导航

 

【题目描述】

给定一个序列,有两个操作。

U--将第A个数改成B。

Q--询问[a,b]区间内最长的连续上升子序列。

【算法分析】

线段树的区间合并。

s[n][0]表示以区间左端点开头的上升子序列长度,s[n][1]表示以区间右端点结尾的上升子序列长度s[n][2]表示整个区间最长的上升子序列长度。

ps.更新s[n][2]的地方写的不够简洁,还能优化一下代码。

#include<cstdio>
#define N 100010
#define lson l,m,n<<1
#define rson m+1,r,n<<1|1
using namespace std;
int s[N<<2][3];
int x[N];
int max(int a,int b,int c){
    int ans1=a>b?a:b;
    return ans1>c?ans1:c;
}
int min(int a,int b){
    return a<b?a:b;
}
void build(int l,int r,int n){
    if(l==r){
        s[n][0]=1,s[n][1]=1,s[n][2]=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    s[n][0]=s[n<<1][0];
    s[n][1]=s[n<<1|1][1];
    int k=0;
    if(x[m]<x[m+1]){
        if(s[n<<1][0]==m-l+1)//左区间左端点的序列长贯穿整个左区间
            s[n][0]+=s[n<<1|1][0];
        if(s[n<<1|1][1]==r-m)//同上,判断右区间
            s[n][1]+=s[n<<1][1];
        k=s[n<<1][1]+s[n<<1|1][0];
    }
    else
    k=max(s[n<<1][1],s[n<<1|1][0],k);
    s[n][2]=max(s[n][0],s[n][1],k);
    s[n][2]=max(s[n][2],s[n<<1][2],s[n<<1|1][2]);
}
void update(int nn,int l,int r,int n){
    if(l==r)
    return;
    int m=(l+r)>>1;
    if(nn<=m)
    update(nn,lson);
    else
    update(nn,rson);
    s[n][0]=s[n<<1][0];
    s[n][1]=s[n<<1|1][1];
    int k=0;
    if(x[m]<x[m+1]){
        if(s[n<<1][0]==m-l+1)
            s[n][0]+=s[n<<1|1][0];
        if(s[n<<1|1][1]==r-m)
            s[n][1]+=s[n<<1][1];
        k=s[n<<1][1]+s[n<<1|1][0];
    }
    else
    k=max(s[n<<1][1],s[n<<1|1][0],k);
    s[n][2]=max(s[n][0],s[n][1],k);
    s[n][2]=max(s[n][2],s[n<<1][2],s[n<<1|1][2]);
}
int query(int ll,int rr,int l,int r,int n){
    if(ll==l&&rr==r)
        return s[n][2];
    int m=(l+r)>>1;
    if(rr<=m)
    return query(ll,rr,lson);
    else if(ll>m)
    return query(ll,rr,rson);
    else{
        int k1=query(ll,m,lson);
        int k2=query(m+1,rr,rson);
        int k3=0;
        if(x[m]<x[m+1])
            k3=min(s[n<<1][1],m-ll+1)+min(s[n<<1|1][0],rr-m);
        return max(k1,k2,k3);
    }
}
int main(){
//    freopen("in.txt","r",stdin);
    int t,m,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        scanf("%d",&x[i]);
        build(1,n,1);
        for(int i=1;i<=m;i++){
            char c[5];
            int a,b;
            scanf("%s%d%d",c,&a,&b);
            if(c[0]=='U'){
                x[a+1]=b;
                update(a+1,1,n,1);
            }
            else if(c[0]=='Q'){
                printf("%d\n",query(a+1,b+1,1,n,1));
            }
        }
    }
    return 0;
}

  

posted on 2012-08-01 22:39  dreamxr  阅读(134)  评论(0编辑  收藏  举报