hdu 3308 线段树-区间连续最长上升子序列

本文介绍了一个特定的编程问题——求解区间内最长连续递增子序列(LCIS),并通过线段树分治的方法给出了高效的解决方案。文章详细展示了如何利用线段树维护区间属性,并通过实例说明了算法的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LCIS

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4842    Accepted Submission(s): 2166


Problem 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<=105).
The next line has n integers(0<=val<=105).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=105)
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


求区间连续最长子序列,用线段树分治的思想做。某个区间的[l,r]的最长子序列,将区间分解成两部分,最长部分可能在[l,m]、[m+1,r]、或者部分在左半部部分在右半部份。

对于第三种情况,其长度为左半部分的右端点开始逆向的最长下降长度+右半部份的左端点为起点的最长上升长度(前提a[m]<a[m+1])。


#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
using namespace std;

#define maxn 300005
#define getc int m=(l+r)>>1, lc=rt<<1,rc=rt<<1|1

int lk[maxn],rk[maxn],ls[maxn],rs[maxn],s[maxn];
int a[maxn/3];

void push_up(int rt, int l, int r)
{
    getc;
    lk[rt]=lk[lc],rk[rt]=rk[rc];
    s[rt]=max(s[lc], s[rc]);
    if(rk[lc]<lk[rc])
        s[rt]=max(s[rt], rs[lc]+ls[rc]);
    ls[rt]=ls[lc];
    if(ls[lc]==m-l+1 && rk[lc]<lk[rc])
        ls[rt]=ls[lc]+ls[rc];
    rs[rt]=rs[rc];
    if(rs[rc]==r-m && rk[lc]<lk[rc])
        rs[rt]=rs[rc]+rs[lc];
}
void build(int rt, int l, int r)
{
    if(l==r){
        lk[rt]=rk[rt]=a[l];
        s[rt]=ls[rt]=rs[rt]=1;
        return;
    }
    getc;
    build(lc, l, m);
    build(rc, m+1, r);
    push_up(rt, l, r);
}

void update(int rt, int l, int r, int k, int v)
{
    if(l==r){
        lk[rt]=rk[rt]=v;
        s[rt]=ls[rt]=rs[rt]=1;
        return;
    }
    getc;
    if(k<=m)
        update(lc, l, m, k, v);
    else
        update(rc, m+1, r, k, v);
    push_up(rt, l, r);
}

int lquery(int rt, int l, int r, int ll, int rr)
{
    if(ll<=l && r<=rr){
        return ls[rt];
    }
    getc;
    int ret=lquery(lc, l, m, ll, min(rr, m));
    if(rr>m && ret==m-l+1 && rk[lc]<lk[rc])
        ret+=lquery(rc, m+1, r, m+1, rr);
    return ret;
}
int rquery(int rt, int l, int r, int ll, int rr)
{
    if(ll<=l && r<=rr){
        return rs[rt];
    }
    getc;
    int ret=rquery(rc, m+1, r, max(ll, m+1), rr);
    if(ll<=m && ret==r-m && rk[lc]<lk[rc])
        ret+=rquery(lc, l, m, ll, m);
    return ret;
}

int query(int rt, int l, int r, int ll, int rr)
{
    if(ll<=l && r<=rr){
        return s[rt];
    }
    getc;
    if(rr<=m)
        return query(lc, l, m, ll, rr);
    else if(ll>m)
        return query(rc, m+1, r, ll, rr);
    else{
        int ret=max(query(lc, l, m, ll, m), query(rc, m+1, r, m+1, rr));
        if(rk[lc]<lk[rc])
            ret=max(ret, rquery(lc, l, m, ll, m)+lquery(rc, m+1, r, m+1, rr));
        return ret;
    }
}



int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        int n,m;
        scanf("%d%d", &n, &m);
        for(int i=1; i<=n; i++)
            scanf("%d", a+i);
        build(1, 1, n);
        char s[3];
        int a,b;
        while(m--){
            scanf("%s%d%d", s, &a,&b);
            a++;
            if(s[0]=='U'){
                update(1, 1,n, a, b);
            }
            else{
                b++;
                printf("%d\n", query(1, 1, n, a,b));
            }
        }
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值