zoukankan      html  css  js  c++  java
  • hdu3308LCIS(线段树,点更新,段查寻,查寻时一定要注意跨越时如何计算)

    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<=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
    题意:输入Q,则查寻范围[A,B]内的最长升序,输入U,则更新点A的值变成B。
    解题:记录第个节点的最左端的升序长度,最右端的升序的长度和在这个范围内的最长升序。而父节点的则是由左右节点产生。
    1. 左儿子最右边的值 < 右儿子最左边的值
    
        lMax = (左儿子的lMax == 左儿子的len) ? 左儿子的len + 右儿子的lMax : 左儿子的lMax;
        rMax = (右儿子的rMax == 右儿子的len) ? 右儿子的len + 左儿子的rMax : 右儿子的rMax;
        Max  = MAX(左儿子的rMax + 右儿子的lMax, 左儿子的Max, 右儿子的Max, lMax, rMax);
    
    2. 左儿子最右边的值 >= 右儿子最左边的值
        lMax = 左儿子的lMax;
        rMax = 右儿子的rMax;
        Max  = MAX(左儿子的Max, 右儿子的Max);
    注意:在查寻时,当跨越左右子树时则一这要注意这个,当 左节点的最右边的值< 右节点的最左边的值时,那么有可能最长升序在这时最大,并且不能超过这个范围。
    #include<stdio.h>
    #define N 500010
    struct node
    {
        int Llcis,Rlcis,lcis;//最左连续升序长度,最右连续升序长度,这个范围的最长连续升序长度
    }tree[8*N];
    int num[N+5];
    int max(int a,int b){ return a>b?a:b;}
    void chang_tree(int l,int r,int k)//根据第K个节点的左右节点,计算第K个节点的最左,最右和最长 的升序长度
    {
        int m=(l+r)/2;
         node ltree=tree[k*2],rtree=tree[k*2+1];
        if(num[m]>=num[m+1])//当左节点的最右边的值不小右节点的最左边的值时
        {
            tree[k].Llcis=ltree.Llcis;
            tree[k].Rlcis=rtree.Rlcis;
            tree[k].lcis=max(ltree.lcis,rtree.lcis);
        }
        else
        {
            if(m-l+1==ltree.Llcis) tree[k].Llcis=ltree.Llcis+rtree.Llcis;
               else  tree[k].Llcis=ltree.Llcis;
            if(r-m==rtree.Rlcis) tree[k].Rlcis=rtree.Rlcis+ltree.Rlcis;
                else  tree[k].Rlcis=rtree.Rlcis;
            tree[k].lcis=max(ltree.lcis,ltree.Rlcis+rtree.Llcis);
            tree[k].lcis=max(tree[k].lcis,rtree.lcis);
            tree[k].lcis=max(tree[k].lcis,tree[k].Llcis);
            tree[k].lcis=max(tree[k].lcis,tree[k].Rlcis);
        }
    }
    void build(int l,int r,int k)
    {
        int m=(l+r)/2;
        if(l==r){
            tree[k].Llcis=1;
            tree[k].lcis=1;
            tree[k].Rlcis=1;
            return ;
        }
        build(l,m,k*2);
        build(m+1,r,k*2+1);
        chang_tree(l,r,k);
    }
    void updata(int l,int r,int k,int Q,int ans)
    {
        int m=(l+r)/2;
        if(l==Q&&Q==r)
        {num[Q]=ans; return ;}
        if(Q<=m) updata(l,m,k*2,Q,ans);
        if(Q>m) updata(m+1,r,k*2+1,Q,ans);
        chang_tree(l,r,k);
    }
    int maxlen;
    void find(int l,int r,int k,int L,int R)
    {
        int m=(l+r)/2;
        if(L<=l&&r<=R){
               maxlen=max(tree[k].lcis,maxlen);
               return ;
        }
        if(R<=m) find(l,m,k*2,L,R);
        else if(L>m) find(m+1,r,k*2+1,L,R);
        else{
            find(l,m,k*2,L,R);
            find(m+1,r,k*2+1,L,R);
        //-----当查寻夸越左右子树时,左子树的最右端点的值小于右子树的最左端点的值------
            if(num[m]<num[m+1])
                if(L<=m-tree[2*k].Rlcis+1&&m+tree[k*2+1].Llcis<=R)//注意这个条件
               maxlen=max(tree[k*2].Rlcis+tree[k*2+1].Llcis,maxlen);
                else if(L<=m-tree[2*k].Rlcis+1&&m+tree[k*2+1].Llcis>R)//注意这个条件
                  maxlen=max(tree[k*2].Rlcis+R-m,maxlen);
                else if(L>m-tree[2*k].Rlcis+1&&m+tree[k*2+1].Llcis<=R)//注意这个条件
                    maxlen=max(m-L+1+tree[k*2+1].Llcis,maxlen);
                else maxlen=R-L+1;//最长的升序长度
        }
    }
    int main()
    {
        int t,n,m,QL,QR;
        char c[2];
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            scanf("%d",&num[i]);
            build(1,n,1);
            while(m--)
            {
                scanf("%s%d%d",c,&QL,&QR);
                if(c[0]=='U') updata(1,n,1,QL+1,QR);
                if(c[0]=='Q')
                {
                    maxlen=0; find(1,n,1,QL+1,QR+1);
                    printf("%d
    ",maxlen);
                }
            }
        }
    }
    


  • 相关阅读:
    使用jenkins发布docker容器
    使用jenkins构建和部署前端(jenkins是k8s集群中搭建)
    kubernetes的ingress-nginx使用案例
    使用jenkins的SSH Publishers远程执行
    kubernetes集群:向pod里的/etc/hosts添加解析
    kubernetes集群:nacos搭建
    JavaBean的概念
    Statement与PreparedStatement的区别
    JDBC的概念&使用步骤
    session的用法
  • 原文地址:https://www.cnblogs.com/pangblog/p/3357876.html
Copyright © 2011-2022 走看看