初识splay tree (一)

本来是要做hihocoder 1034 毁灭者问题,发现朴素的数据结构无法满足该题目如此BT的要求,随查了一下,splay tree貌似可以解决,于是目标转到了学习splay tree上。
学习splay tree 的主要参考资料:
《伸展树的基本操作与应用》– 杨思雨
《运用伸展树解决数列维护问题》– By Crash
《Splaying a Search Tree in Preorder Takes Linear Time》
《NOI 2005 维护数列》– ByVoid
《NOI 2005 维护数列 测试数据》
太晚了,具体操作原理、细节明天再更新。。
这里先发一个poj3468 A Simple Problem with Integers AC代码,当做初学splay tree的第一道测试题。

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define ll64 long long int 
struct st{
    struct node{
        long long int size,value,cover,sums;
        struct node *pre,*ch[2];
    };  
    node *nill,*root;
    node buf[200000]; int bufsize;
    int pushdown(node *x){
        if(x==nill || x==NULL) return 0;
        if(x->cover){
            x->value+=x->cover; x->sums+=x->cover*x->size; 
            x->ch[0]->cover+=x->cover;
            x->ch[1]->cover+=x->cover;
            x->cover=0;
        }
        return 0;
    }
    int update(node *x){
        if(x==nill || x==NULL) return 0;
        pushdown(x->ch[0]);pushdown(x->ch[1]);
        x->size = x->ch[0]->size+x->ch[1]->size+1;
        x->sums=x->ch[0]->sums+x->ch[1]->sums+x->value;
        return 0;
    }
    node *getnode(ll64 value,node *fa){
        node *p=buf+bufsize++;
        p->cover=0;
        p->value=p->sums=value;
        p->size=1;
        p->ch[0]=p->ch[1]=nill; p->pre=fa;
        return p;
    }
    int init(){
        bufsize=0; nill=root=NULL;
        nill=getnode(0,NULL);
        nill->size=0; nill->ch[0]=nill->ch[1]=NULL;
        root=getnode(0,nill);
        root->ch[1]=getnode(0,root);
        return 0;
    }
    int rotateto(node*x,int to){
        node *y=x->pre;
        y->ch[to^1]=x->ch[to];
        y->ch[to^1]->pre=y;
        x->pre=y->pre;
        if(y==y->pre->ch[0])x->pre->ch[0]=x;
        else x->pre->ch[1]=x;
        x->ch[to]=y; y->pre=x;
        update(y);
        if(y==root) root=x;
        return 0;
    }
    int splay(node *x,node *fa){
        pushdown(x);
        while(x->pre!=fa ){
            if(x->pre->pre==fa){
                if(x->pre->ch[0]==x) rotateto(x,1);
                else rotateto(x,0);
            }else{
                if(x->pre->pre->ch[0]==x->pre){
                    if(x->pre->ch[0]==x){rotateto(x->pre,1);rotateto(x,1);}
                    else{rotateto(x,0);rotateto(x,1);}
                }else{
                    if(x->pre->ch[0]==x){rotateto(x,1);rotateto(x,0);}
                    else{rotateto(x->pre,0);rotateto(x,0);}
                }

            }

        }
        update(x);
        return 0;
    }
    int select(int k,node *fa){
        node *rt=root;
        while(rt!=nill){
            pushdown(rt);
            if(rt->ch[0]->size == k-1) break;
            else if(rt->ch[0]->size>k-1) rt=rt->ch[0];
            else {k-=rt->ch[0]->size+1; rt=rt->ch[1];}
        }
        splay(rt,fa);
        return 0;
    }
    int insert(int pos,int tot){
        node *p,*q;
        long long int s;
        scanf("%lld",&s);
        p=q=getnode(s,nill);
        for(int i=1;i<tot;i++){
            scanf("%lld",&s);
            p=p->ch[1]=getnode(s,p);
        }
        select(pos+1,nill);
        select(pos+2,root);
        root->ch[1]->ch[0]=q; q->pre=root->ch[1];
        splay(p,nill);
        return 0;
    }
    int add(int a,int b,long long int c){
        select(a,nill);
        select(b+2,root);

        root->ch[1]->ch[0]->cover+=c;
        splay(root->ch[1]->ch[0],nill);
        return 0;
    }
    ll64 getsums(int a,int b){
        select(a,nill);
        select(b+2,root);
    //  cout<<root->value<<" "<<root->ch[1]->value<<endl;
        pushdown(root->ch[1]->ch[0]);
        return root->ch[1]->ch[0]->sums;
    }
};

int main(){
    int n,q;
    scanf("%d %d",&n,&q);
    st *str=new st;
    str->init();
    str->insert(0,n);
    char s[10]; ll64 c;
    int a,b;
    for(int i=0;i<q;i++){
        scanf("%s %d %d",s,&a,&b);
        //cout<<s<<" "<<a<<" "<<b<<endl;
        if(s[0]=='Q'){
            printf("%lld\n",str->getsums(a,b));
        }else{
            scanf("%lld",&c);
            str->add(a,b,c);
        }   
    }
    return 0;
}

同时还查到了一个有意思的问题,在这里记下:

《动态树问题及其应用》

扫码关注作者,定期分享技术、算法类文章
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值