hdu 4699 Editor(splay tree 伸展树)

hdu 4699  Editor

题意:对一个数列进行操作,光标位置后面插入一个权值为x的数,删除光标前的那个数,光标左移一位,光标右移一位,求到k位置的最大的前缀和。。

解题思路:标乘是用了栈进行维护。。我这智商比较捉急啊,用了splay。节点下要记录的是该几点所掌控的子树的前缀最大值是多少,那么要维护这个最大值,就需要一个辅助变量,sum[rt]表示rt节点所掌控的子树的所有数的和,怎么维护前缀最大,看下我的push_up ()函数就知道了,还是很好理解的。左右移,插入,删除都是很常见的splay的操作了,不解释这个了。然后就是询问,询问的时候我们只要把k大的所在的节点转到根,那么根的左儿子所保存的那个最大前缀的信息,自然就是1-(k-1)的所有前缀和里面最大的了,再用左儿子的sum+val[rt]去比较,得出的较大的那个就是答案了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std ;

const int maxn = 1000011 ;

int son[2][maxn] , fa[maxn] , size[maxn] ;
int val[maxn] , sum[maxn] , mm[maxn] ;
int tot ;

void push_up ( int x ) {
    size[x] = 1 ;
    sum[x] = val[x] ;
    int ls = son[0][x] , rs = son[1][x] ;
    if ( son[0][x] ) size[x] += size[son[0][x]] , sum[x] += sum[son[0][x]] ;
    if ( son[1][x] ) size[x] += size[son[1][x]] , sum[x] += sum[son[1][x]] ;
    if ( ls ) {
        mm[x] = max ( mm[ls] , sum[ls] + val[x] ) ;
        if ( rs ) mm[x] = max ( mm[x] , sum[ls] + val[x] + mm[rs] ) ;
    }
    else {
        mm[x] = val[x] ;
        if ( rs ) mm[x] += mm[rs] > 0 ? mm[rs] : 0 ;
    }
}

void rot ( int x , int c ) {
    int y = fa[x] , z = fa[y] ;
    son[!c][y] = son[c][x] ;
    if ( son[c][x] ) fa[son[c][x]] = y ;
    fa[x] = z ;
    if ( z ) {
        if ( y == son[0][z] ) son[0][z] = x ;
        else son[1][z] = x ;
    }
    son[c][x] = y , fa[y] = x ;
    push_up ( y ) ;
}

void splay ( int x , int to ) {
    while ( fa[x] != to ) {
        if ( fa[fa[x]] == to ) rot ( x , x == son[0][fa[x]] ) ;
        else {
            int y = fa[x] , z = fa[y] ;
            if ( x == son[0][y] ) {
                if ( y == son[0][z] ) rot ( y , 1 ) , rot ( x , 1 ) ;
                else rot ( x , 1 ) , rot ( x , 0 ) ;
            }
            else {
                if ( y == son[1][z] ) rot ( y , 0 ) , rot ( x , 0 ) ;
                else rot ( x , 0 ) , rot ( x , 1 ) ;
            }
        }
    }
    push_up ( x ) ;
}

int join ( int r1 , int r2 , int rt ) {//合并以x为根的左右子树
    if ( !r1 ) {
        if ( !r2 ) return 0 ;
        fa[r2] = 0 ;
        return r2 ;
    }
    int x = r1 ;
    while ( son[1][x] ) x = son[1][x] ;
    splay ( x , rt ) ;
    son[1][x] = r2 ;
    if ( r2 ) fa[r2] = x ;
    fa[x] = 0 ;
    push_up ( x ) ;
    return x ;
}

int new_node ( int v ) {
    size[++tot] = 1 ;
    val[tot] = v ;
    son[0][tot] = son[1][tot] = fa[tot] = 0 ;
    return tot ;
}

int find ( int v , int rt ) {
    int cnt = 0 ;
    if ( son[0][rt] ) cnt += size[son[0][rt]] ;
    if ( cnt + 1 == v ) return rt ;
    if ( cnt >= v ) return find ( v , son[0][rt] ) ;
    return find ( v - cnt - 1 , son[1][rt] ) ;
}

int main () {
    int q , a , b , n ;
    char op[111] ;
    while ( scanf ( "%d" , &q )!= EOF ) {
        int pos = 0 , rt = 0 ;
        tot = 0 ;
        while ( q -- ) {
            scanf ( "%s" , op ) ;
            n = size[rt] ;
            if ( op[0] == 'Q' ) {
                scanf ( "%d" , &a ) ;
                int temp = find ( a , rt ) ;
                splay ( temp , 0 ) ;
                rt = temp ;
                temp = son[0][rt] ;
    //            printf ( "temp = %d , mm = %d, sum = %d , val = %d\n" , temp , mm[temp] , sum[temp] , val[rt] ) ;
                int ans ;
                if ( temp )
                    ans = max ( mm[temp] , sum[temp] + val[rt] ) ;
                else ans = val[rt] ;
                printf ( "%d\n" , ans ) ;
            }
            else if ( op[0] == 'L' ) pos -= ( pos != 0 ) ;
            else if ( op[0] == 'R' ) pos += ( pos != n ) ;
            else if ( op[0] == 'I' ) {
                scanf ( "%d" , &a ) ;
                int temp = new_node ( a ) ;
                if ( pos == 0 ) {
                    son[1][temp] = rt ;
                    if ( son[1][temp] ) fa[son[1][temp]] = temp ;
                    rt = temp ;
                    push_up ( rt ) ;
                }
                else {
                    int fuck = find ( pos , rt ) ;
                    splay ( fuck , 0 ) ;
                    rt = fuck ;
                    son[1][temp] = son[1][rt] ;
                    if ( son[1][temp] ) fa[son[1][temp]] = temp ;
                    fa[temp] = rt , son[1][rt] = temp ;
                    push_up ( temp ) ;
                    push_up ( rt ) ;
                }
                pos ++ ;
            }
            else {
                int fuck = find ( pos , rt ) ;
                splay ( fuck , 0 ) ;
                rt = fuck ;
                rt = join ( son[0][rt] , son[1][rt] , rt ) ;
                pos -- ;
            }
        }
    }
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值