spoj4487(splay)

Splay不加反转(Push_down)版本,求区间最大值,维护每个点的子树的整个sum和
中间(内部)最大值:msum,lsum(左侧连续最大值)rsum右侧连续最大值,和线段树基本一致)
splay(int &x,int pos)是指把现在x这个根的子树做变化,使得这个根变成这个子树里面第pos位(中序遍历)splay整棵树的中序遍历就是我们维护的动态数组,比如添加一个数到数组里第5个位置的时候,可以考虑根的左儿子有3个,根就是第4个,如果根的右儿子是第5个,那么显然根的右儿子的左儿子添加数字的话就正好插在整个树的第5个,操作就是把4先旋到整个树的根,再把旋完的跟的右子树的根旋成这个子树的第1个,这个左儿子就是空的了,把要插的插进去,其余操作都相同

/*
Splay不加反转(Push_down)版本,求区间最大值,维护每个点的子树的整个sum和
中间(内部)最大值:msum,lsum(左侧连续最大值)rsum右侧连续最大值,和线段树基本一致)
*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200009;
const int inf = 2000000000+1;
int siz[maxn],s[maxn][2],tot,val[maxn],n,m;
int lsum[maxn];   //[left, x)
int rsum[maxn];   //(x, right]
int msum[maxn],sum[maxn];   //m:inside
#define ls s[x][0]
#define rs s[x][1]
int p,root;
int fd(int x,int k){//-1:根 1:右 0:左
    if(ls == -1){
        if(k == 1) return -1;
        else return 1;
    }
    else{
        if(k <= siz[ls]) return 0;
        else if(k == siz[ls]+1) return -1;
        else return 1;
    }
}
void Push_up(int x){
    siz[x] = (ls==-1?0:siz[ls])+(rs==-1?0:siz[rs])+1;
    sum[x] =  val[x] + (ls == -1?0:sum[ls])+ (rs == -1?0:sum[rs]);
    if(ls == -1 && rs == -1){
        lsum[x] = rsum[x] = msum[x] = val[x];
    }
    else if(ls != -1 && rs != -1){
        //printf("lsum[%d] = %d  %d\n",ls,lsum[ls],sum[ls]);
        lsum[x] = max(lsum[ls], sum[ls] + val[x] + max(lsum[rs], 0));
        rsum[x] = max(rsum[rs], sum[rs] + val[x] + max(rsum[ls], 0));
        msum[x] = max( max(msum[ls], msum[rs]),val[x] + max(rsum[ls], 0) + max(lsum[rs], 0) );
    }
    else if(ls == -1 && rs != -1){
        lsum[x] = val[x] + max( lsum[rs], 0 );
        rsum[x] = max(rsum[rs], sum[rs] + val[x] );
        msum[x] = max(msum[rs],val[x] + max(lsum[rs], 0) );
    }
    else{
        lsum[x] = max(lsum[ls], sum[ls] + val[x] );
        rsum[x] = val[x] + max(rsum[ls], 0);
        msum[x] = max(msum[ls],val[x] + max(rsum[ls], 0));
    }
}
void Rotate(int &x,int d){//d = 0:x右儿子变成跟,1:左变根
    int k = s[x][d^1];s[x][d^1] = s[k][d];s[k][d] = x;
    Push_up(x); Push_up(k);
    x = k;
}
void Splay(int &x,int k){
    int d = fd(x,k);
    if(d == -1) return ;
    if(d == 1) k -= (ls==-1?0:siz[ls])+1;
    int p = s[x][d];
    int d2 = fd(p,k),k2;
    //注释以d = 0为例
    if(d2 == 0)         k2 = k;
    else if(d2 == 1)    k2 = k-(s[p][0]==-1?0:siz[ s[p][0] ])-1;
    if(d2 != -1){
        Splay(s[p][d2],k2);
        if(d == d2) Rotate(x,1-d);
        //两次方向一样,例如都是0(往左的链) 把根的第一个儿子(左边)转到根
        else        Rotate(s[x][d],1-d2);
        //两次方向不一样 例如左右,把第一个(根的左边)的右儿子(第二个)转到跟的右侧
    }
    Rotate(x,1-d);//跟的左侧转到跟
}
int new_node(int vl){
    s[tot][0] = s[tot][1] = -1;
    siz[tot] = 1;
    val[tot] = lsum[tot] = rsum[tot] = msum[tot] = sum[tot] = vl;

    return tot++;
}
void Insert(int &x,int pos,int val){//for 1:ro2 1   pos pos-1
    Splay(x,pos-1);
    Splay(rs,pos-1-(ls==-1?0:siz[ls]));
    s[rs][0] = new_node(val);
    Push_up(rs);Push_up(x);
}
void pre(){
    tot = 0;root = 0;
    siz[tot++] = 2;siz[tot++] = 1;s[0][1] = tot-1;
    s[0][0] = s[1][0] = s[1][1] = -1;
    for(int i = 0 ; i <= 1; i++)
        val[i] = sum[i] = lsum[i] = rsum[i] = msum[i] = 0;
}
void out(int x,int h){
    if(x == -1){
        return;
    }
    out(ls,h+1);
    cout<<"|";
    for(int i=0;i<h*4;i++) printf(" ");
    printf("node %d: val=%d siz=%d\n",x,val[x],siz[x]);
    out(rs,h+1);
}
void init(){//插到第二个上
    for(int i = 1; i <= n ; i++){
        scanf("%d",&p);
        Insert(root,i+1,p);
    }
    //out(root,0);
}
void Del(int &x,int pos){
    Splay(x,pos-1);
    Splay(rs,pos+1-1-(ls==-1?0:siz[ls]));
    //Push_up(x);
    s[rs][0] = -1;
    Push_up(rs);
    Push_up(x);
}
void Qury(int &x,int l,int r){
    Splay(x,l-1);
    Splay(rs,r+1-1-(ls==-1?0:siz[ls]));
    Push_up(rs);
    Push_up(x);
}
void Rep(int &x,int pos,int vl){
    Splay(x,pos-1);
    Splay(rs,pos+1-1-(ls==-1?0:siz[ls]));
    val[s[rs][0]] = sum[s[rs][0]] = lsum[s[rs][0]] = rsum[s[rs][0]] = msum[s[rs][0]] = vl;
    Push_up(rs);Push_up(x);
}
char op[3];
int _pos,_add,l,r,vl;
void sov(){
    scanf("%d",&m);
    for(int i =1; i <= m ; i++){
        scanf("%s",op);

        //cout<<i<<": "<<op<<"\n";
        if(op[0] == 'I'){
            scanf("%d%d",&_pos,&_add);
            Insert(root,_pos+1,_add);
        }
        if(op[0] == 'D'){
            scanf("%d",&_pos);
            Del(root,_pos+1);
        }
        if(op[0] == 'Q'){
            scanf("%d%d",&l,&r);
            Qury(root,l+1,r+1);
            printf("%d\n",msum[ s[ s[root][1] ][ 0 ] ]);
        }
        if(op[0] == 'R'){
            scanf("%d%d",&_pos,&vl);
            Rep(root,_pos+1,vl);
        }

        //out(root,0);
        //cout<<endl;
    }
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    scanf("%d",&n);
    pre();
    init();
    //out(root);
    sov();
}
/*
5
3 -4 3 -1 6
10
I 6 2
Q 3 5
R 5 -4
Q 3 5
D 2
Q 1 5
I 2 -10
Q 1 6
R 2 -1
Q 1 6
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值