hdu 3308 线段树区间更新

<span style="font-family: Arial, Helvetica, sans-serif;">#include<iostream></span>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstdlib>
using namespace std;
struct  Node
{
    int l_value,r_value;             //左端点,右端点值
    int l_max,r_max; <span style="white-space:pre">		</span>     //  左,右端点开始的最大LCIS 
    int l,r,max; <span style="white-space:pre">		</span>     // 区间的左右端点位置  max值指该区间内最大的LCIS  (可能是l_max  r_max中之一)
};
Node tree[400024];
int num[100024];
int Max( int a , int b )
{
    return a>b? a:b;
}
Node Update( Node a ,Node b )          //整段代码的重中之重   其他的操作都是很常见且很容易理解的  关于在于区间的合并操作。
{
    Node t;
    t.l=a.l,t.r=b.r;
    t.l_value=a.l_value;                 //首先由左右孩子更新父亲的左右端点的值,也更新左右端点的位置
    t.r_value=b.r_value;
    if(a.r_value<b.l_value&&a.l_max==(a.r-a.l+1))     //如果左孩子的左端点开始的LCIS值是整个左孩子长度 同时左孩子右端点值小于右孩子左端点值 此时更新父亲节点的左端点开始的LCIS 长度为两个孩子的左端点和
        t.l_max=a.l_max+b.l_max; 
    else t.l_max=a.l_max;      //如果左右孩子无法连接   那么单独更新
    if(a.r_value<b.l_value&&b.r_max==(b.r-b.l+1))
        t.r_max=a.r_max+b.r_max;
    else t.r_max=b.r_max;         //右孩子操作同左孩子一样  
    if(a.r_value<b.l_value)
        t.max=Max(Max(a.max,b.max),a.r_max+b.l_max);    //  更新父亲的max值   如果可以连接   那么max值的来源有三项  否则两项
    else t.max=Max(a.max,b.max);
    return t;
}
void Maketree( int l , int r, int cnt )
{
    tree[cnt].l = l;
    tree[cnt].r = r;
    tree[cnt].l_value = num[l];
    tree[cnt].r_value = num[r];
    if( l == r )
    {
        tree[cnt].l_max = tree[cnt].r_max = tree[cnt].max = 1;
        return ;
    }
    int mid = ( l + r )>>1;
    Maketree( l , mid  ,cnt*2 );
    Maketree( mid + 1 , r , cnt*2+1);
    tree[cnt] = Update( tree[cnt*2] , tree[cnt*2+1] );
}
void Change( int place ,int value, int cnt )
{
    if( place == tree[cnt].l&&tree[cnt].r == place )
    {
        tree[cnt].r_value = tree[cnt].l_value = value;
        return ;
    }
    int mid = ( tree[cnt].r + tree[cnt].l )>>1;
    if( place > mid ) Change( place , value , cnt*2+1 );
    else Change( place ,value , cnt*2 );
    tree[cnt] = Update( tree[cnt*2] , tree[cnt*2+1] );
}
Node Query( int l , int r, int cnt )
{
    if( l<=tree[cnt].l&&r>=tree[cnt].r )
        return tree[cnt];
    int mid = (tree[cnt].l + tree[cnt].r)>>1;
    if( l > mid  ) return Query( l , r , cnt*2+1 );
    else if( r <= mid ) return Query( l ,r ,cnt *2  );
    else
    {
        Node a,b;
        a = Query( l , mid , cnt*2 );
        b = Query( mid + 1, r ,cnt*2 + 1);
        return Update( a ,b );
    }
}
int main( )
{
    int n,N,m,A,B;
    char c[4];
    while( scanf( "%d",&N )==1 )
    {
        while( N-- )
        {
            scanf( "%d%d",&n,&m );
            for( int i = 0; i< n ;i++ )
                scanf( "%d",&num[i] );
            Maketree( 0 , n-1 , 1 );
            for( int i = 0 ; i< m ; i++ )
            {
                scanf( "%s%d%d",c , &A ,&B );
                if( c[0]=='U' )
                {
                    Change( A , B , 1 );
                }
                else
                {
                    Node t = Query( A , B ,1 );
                    printf( "%d\n",t.max );
                }
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值