【HDU - 3308】 LCIS 【线段树+单点更新+区间合并】

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
没思路,Orz 一下大佬们。
解看代码吧。
代码

#include<bits/stdc++.h>
using namespace std;
#define  LL long long
#define fread() freopen("in.txt","r",stdin)
#define fwrite() freopen("out.txt","w",stdout)
#define CLOSE() ios_base::sync_with_stdio(false)

const int MAXN = 1e5+10;
const int MAXM = 1e6;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;

struct Tree{
    int l, r, len;//区间左右端点 和 长度  
    int lv, rv;//区间左端点的值  右端点的值  
    int lsum, rsum;//以区间左端点为起点的最长递增序列长度 以区间右端点为终点的最长递增序列长度  
    int sum;//区间 最长递增序列长度 
}tree[MAXN<<2];

void Up(int o){
    tree[o].lv=tree[o<<1].lv;
    tree[o].rv=tree[o<<1|1].rv;
    tree[o].lsum=tree[o<<1].lsum;
    tree[o].rsum=tree[o<<1|1].rsum;
    tree[o].sum=max(tree[o<<1].sum,tree[o<<1|1].sum);
    if(tree[o<<1].rv<tree[o<<1|1].lv){
        if(tree[o<<1].lsum==tree[o<<1].len)   //左半区间完全容纳最长递增序列 向右延伸
            tree[o].lsum+=tree[o<<1|1].lsum;
        if(tree[o<<1|1].rsum==tree[o<<1|1].len) //右半区间完全容纳最长递增序列 向左延伸  
            tree[o].rsum+=tree[o<<1].rsum;
        tree[o].sum=max(tree[o].sum,max(tree[o].lsum,tree[o].rsum));  //更新 
        tree[o].sum=max(tree[o].sum,tree[o<<1].rsum+tree[o<<1|1].lsum);
    }
}
void Build(int o,int le,int ri){
    tree[o].l=le;tree[o].r=ri;tree[o].len=ri-le+1;
    if(le==ri){
        int val;scanf("%d",&val);
        tree[o].lv=tree[o].rv=val;
        tree[o].lsum=tree[o].rsum=tree[o].sum=1;
        return ;
    }
    int mid=(tree[o].l+tree[o].r)>>1;
    Build(o<<1,le,mid);
    Build(o<<1|1,mid+1,ri);
    Up(o);
}
void UpDate(int o,int pos,int val){
    if(tree[o].l==tree[o].r){
        tree[o].lv=tree[o].rv=val;
        return ;
    }
    int mid=(tree[o].l+tree[o].r)>>1;
    if(pos<=mid) UpDate(o<<1,pos,val);
    else UpDate(o<<1|1,pos,val);
    Up(o);
}
int Query(int o,int le,int ri){
    if(le<=tree[o].l&&tree[o].r<=ri) {
        return tree[o].sum;
    }
    int mid=(tree[o].l+tree[o].r)>>1;
    if(ri<=mid) return Query(o<<1,le,ri);
    else if(le>mid) return Query(o<<1|1,le,ri);
    else {
        int a=Query(o<<1,le,mid);
        int b=Query(o<<1|1,mid+1,ri);
        int ans=max(a,b);
        if(tree[o<<1].rv<tree[o<<1|1].lv) {  //  不在区间里的话,会查询两个部分的最大值,
        //但是其实这两个部分是连着的,所以有的这里的代码 
            ans=max(ans,min(tree[o<<1].rsum,mid-le+1)+min(tree[o<<1|1].lsum,ri-mid));
        }
        return ans;
    } 
}
int main(){
    CLOSE();
//  fread();
//  fwrite();
    int T;scanf("%d",&T);
    while(T--){
        int n,q;
        scanf("%d%d",&n,&q);
        Build(1,0,n-1);
        char op[5];
        while(q--){
            int a,b;
            scanf("%s%d%d",op,&a,&b);
            if(op[0]=='U') UpDate(1,a,b);
            else printf("%d\n",Query(1,a,b));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值