zoukankan      html  css  js  c++  java
  • LCIS(区间合并)

    LCIS

    Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 12 Accepted Submission(s): 11
     
    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
     
    Author
    notonlysuccess
     
    Source
    HDOJ Monthly Contest – 2010.02.06
     
    Recommend
    wxl
     
    /*
    题意:给你一个长度为n的序列,两种操作:U A B 将第A个数换成B,Q A B 询问区间[A B] 内的最长上升连续子序列的长度
    
    初步思路:首先线段树要维护:此节点的区间 是不是靠左的,是不是靠右的,节点最长的上升子序列的长度,区间左边的值,右
        边的值
    
    #补充:区间合并的时候考虑的方面不全面,如果左儿子是完全的上升连续子序列,右儿子的上升连续子序列左右端点都不占,那
        么这个时候,按照上面的思路,左右儿子就不能合并,这样的话,就会少了一种情况,节点需要维护的值加上,一个区间的
        左端点,右端点,区间连续的长度。
    
    #补充:区间合并已经没问题了,现在的问题就是查询的时候有bug,不能只考虑左右儿子,这样会漏掉很多种情况
    */
    #include<bits/stdc++.h>
    using namespace std;
    /****************************线段树基础模板*********************************/
    const int maxn=100000+5;
    
    #define lson i*2, l, m
    #define rson i*2+1, m+1, r
    struct node{
        int l,r,c;//区间左右端点,区间的长度
        int val_l,val_r;//表示左边的值,表示右边的值
        int res_l,res_m,res_r;//表示左端点,中间,右端点的最长连续上升子序列的长度
    };
    struct Segtree{
    
        node sum[maxn<<2];
    
        void PushUp(int i)//向上更新节点                                      //× √
        {
            //分别比较左右儿子
    
            //这个是不需要讨论的
            sum[i].val_l=sum[i*2].val_l;
            sum[i].val_r=sum[i*2+1].val_r;
            sum[i].res_l=sum[i*2].res_l;//左边界的连续上升子序列的长度肯定是左儿子的
            sum[i].res_r=sum[i*2+1].res_r;//右边界的连续上升子序列的长度肯定是右儿子的
    
            sum[i].res_m=max(sum[i*2].res_m,sum[i*2+1].res_m);//区间的连续上升子序列的长度肯定是的左右的最大值
    
            if(sum[i*2].val_r<sum[i*2+1].val_l){//左右区间可以对接,也就是可以合并的
    
                if(sum[i*2].res_l==sum[i*2].c){//如果左儿子的区间是完全的上升连续序列
    
                    sum[i].res_l+=sum[i*2+1].res_l;//那么i节点的左边界的连续上升序列的长度还要加上右儿子的左边界的连续上升序列的长度
                }
                if(sum[i*2+1].res_r==sum[i*2+1].c){//如果右儿子的区间是完全的上升连续序列
                    sum[i].res_r+=sum[i*2].res_r;
                }
                sum[i].res_m=max(sum[i].res_m,(sum[i*2].res_r+sum[i*2+1].res_l) );//那么i节点的最长上升连续序列还要和左右区间接起来的比较一下
            }
        }
    
        void build(int i,int l,int r)
        {
            sum[i].l=l;
            sum[i].r=r;
            sum[i].c=r-l+1;
            if(l==r)//输入根节点的值并且初始化数据
            {
                scanf("%d",&sum[i].val_l);
                sum[i].val_r=sum[i].val_l;
                // cout<<"i= "<<i<<" "<<sum[i].val_l<<" "<<sum[i].val_r<<endl;
                sum[i].res_r=sum[i].res_l=sum[i].res_m=1;//从左开始的上升组序列的长度,右边的,中间的
                return ;
            }
    
            int m=(l+r)>>1;
            build(lson);
            build(rson);
            PushUp(i);
        }
        int query(int ql,int qr,int i,int l,int r)
        {
            if(ql<=l && r<=qr){
                // cout<<"("<<l<<","<<r<<")"<<" sum[i].res_m="<<sum[i].res_m<<endl;
                return sum[i].res_m;
            }
    
            int m=(l+r)>>1;
            int res=0;
            if(ql<=m) res = max( res,query(ql,qr,lson) );
    
            if(m<qr) res =max( res,query(ql,qr,rson) );
    
            if(sum[2*i].val_r < sum[2*i+1].val_l){//如果左右区间能接起来的话
                // cout<<"i="<<i<<endl;
                // cout<<"min(m-l+1,sum[2*i].res_r)="<<min(m-l+1,sum[2*i].res_r)<<" min(r-m,sum[2*i+1].res_l))="<<min(r-m,sum[2*i+1].res_l)<<endl;
                // cout<<"m-l+1="<<m-l+1<<endl;
                // cout<<"sum[2*i].res_r="<<sum[2*i].res_r<<endl;
                // cout<<"r-m="<<r-m<<endl;
                // cout<<"sum[2*i+1].res_l="<<sum[2*i+1].res_l<<endl;
                res = max(res , min(m-ql+1,sum[2*i].res_r)+min(qr-m,sum[2*i+1].res_l));
            }
            return res;
        }
    
        void update(int id,int val,int i,int l,int r)
        {
            if(l==r)//更新到根节点了
            {
                sum[i].val_l=sum[i].val_r=val;
                return ;
            }
            int m=(l+r)>>1;
            if(id<=m) update(id,val,lson);
            else update(id,val,rson);
    
            PushUp(i);//用来向上回溯
        }
    }segtree;
    /****************************线段树基础模板*********************************/
    int t;
    int n,m;
    char op[2];
    int a,b;
    int main(){
        // freopen("in.txt","r",stdin);
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            //输入
            segtree.build(1,1,n);
    
            // for(int i=1;i<=25;i++){
            //     cout<<"*************************"<<endl;
            //     cout<<"i= "<<i<<endl;
            //     cout<<"l,r,c "<<segtree.sum[i].l<<" "<<segtree.sum[i].r<<" "<<segtree.sum[i].c<<endl;
            //     cout<<"val "<<segtree.sum[i].val_l<<" "<<segtree.sum[i].val_r<<endl;
            //     cout<<"res "<<segtree.sum[i].res_l<<" "<<segtree.sum[i].res_r<<" "<<segtree.sum[i].res_m<<endl;
            // }
    
            for(int i=0;i<m;i++){
                scanf("%s",op);
                // cout<<op<<" ";
                if(op[0]=='U'){//替换
                    scanf("%d%d",&a,&b);
                    // cout<<a<<" "<<b<<endl;
                    a++;
                    segtree.update(a,b,1,1,n);
    
                    // cout<<"update a= "<<a<<" b="<<b<<endl;
                    // cout<<"l,r,c "<<segtree.sum[1].l<<" "<<segtree.sum[1].r<<" "<<segtree.sum[1].c<<endl;
                    // cout<<"val "<<segtree.sum[1].val_l<<" "<<segtree.sum[1].val_r<<endl;
                    // cout<<"res "<<segtree.sum[1].res_l<<" "<<segtree.sum[1].res_r<<" "<<segtree.sum[1].res_m<<endl;
                    // for(int i=1;i<=25;i++){
                    //     cout<<"*************************"<<endl;
                    //     cout<<"i= "<<i<<endl;
                    //     cout<<"l,r,c "<<segtree.sum[i].l<<" "<<segtree.sum[i].r<<" "<<segtree.sum[i].c<<endl;
                    //     cout<<"val "<<segtree.sum[i].val_l<<" "<<segtree.sum[i].val_r<<endl;
                    //     cout<<"res "<<segtree.sum[i].res_l<<" "<<segtree.sum[i].res_r<<" "<<segtree.sum[i].res_m<<endl;
                    // }
                }else{
                    scanf("%d%d",&a,&b);
                    // cout<<a<<" "<<b<<endl;
                    a++;
                    b++;
                    // cout<<"a="<<a<<" b="<<b<<endl;
                    printf("%d
    ",segtree.query(a,b,1,1,n));
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    Android:JNI之Java和C层的相互调用及多线程的回调实现
    高通sdm845_la2.0源码编译及使用QFIL刷机
    git常用指令
    Bouml快速使用指南
    Linux内核数据结构之kfifo详解
    输入系统:进程间双向通信(socketpair+binder)
    Android : 跟我学Binder --- (6) JAVA实现
    【LeetCode】167. Two Sum II
    【LeetCode】1. Two Sum
    【LeetCode】206. Reverse Linked List
  • 原文地址:https://www.cnblogs.com/wuwangchuxin0924/p/6538620.html
Copyright © 2011-2022 走看看