Splay树再学习

队友最近可能在学Splay,然后让我敲下HDU1754的题,其实是很裸的一个线段树,不过用下Splay也无妨,他说他双旋超时,单旋过了,所以我就敲来看下。但是之前写的那个Splay越发的觉得不能看,所以直接学习了大神的Splay树的写法,下面的代码是CLJ上的Splay模板,有很多值得借鉴的地方,代码量比自己写短好多,下面记录下心得。

1.结点标记的add,set直接写在结点里面,更容易理解也更容易明白。

2.pushDown,pushUp也写在Node里,感觉也是漂亮许多。

3.第一次看到的 Node mem[maxn],*C=mem; 写法,这样就不用每次都 &mem[top++],直接就用C++就好,挺好的。

4.写一个作为sentinel的null,这个应该也是一个很重要的认识了吧。

5.旋转和splay两个函数都写的好妙。

6.用get传出【l,r)的区间的结点,之前没有当成一个函数写不太漂亮。

附上大神的模板权当学习。

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<algorithm>

#define INF 0x3fffffff

#define maxn 200100

using namespace std;



struct Node

{

    Node *ch[2],*p;

    int size,val,mx;

    int set; 

    bool rev;

    Node(){

        size=0;

        val=mx=-INF;

        set=-1;

    }

    bool d(){

        return this==p->ch[1];

    }

    void setc(Node *c,int d){

        ch[d]=c;

        c->p=this;

    }

    void setIt(int se){

        set=mx=val=se;

    }

    void revIt(){

        rev^=1;

    }

    void pushDown(); // pushDown();

    void pushUp(){

        size=ch[0]->size+ch[1]->size+1;

        mx=max(val,max(ch[0]->mx,ch[1]->mx));

    }

}Tnull,*null=&Tnull;



Node mem[maxn+50],*C=mem;

int a[maxn+50];



void Node::pushDown(){

    if(set!=-1){

        for(int i=0;i<2;++i){

            if(ch[i]!=null) ch[i]->setIt(set);

        }

        set=-1;

    }

    if(rev){

        swap(ch[0],ch[1]);

        for(int i=0;i<2;++i){

            if(ch[i]!=null) ch[i]->revIt();

        }

        rev=0;

    }

}



Node *make(int v){

    C->ch[0]=C->ch[1]=null;

    C->size=1;

    C->val=C->mx=v;

    C->set=-1;C->rev=0;

    return C++;

}



Node *build(int l,int r)

{

    if(l>=r) return null;

    int m=(l+r)>>1;

    Node *t=make(a[m]); // 根据数组建值,建空值则t=make(0);

    t->setc(build(l,m),0);

    t->setc(build(m+1,r),1);

    t->pushUp();

    return t;

}



Node *root;



void rot(Node *t){

    Node *p=t->p;

    p->pushDown();

    t->pushDown();

    int d=t->d();

    p->p->setc(t,p->d());

    p->setc(t->ch[!d],d);

    t->setc(p,!d);

    p->pushUp();

    if(p==root)

        root=t;

}



void splay(Node *t,Node *f=null){

    while(t->p!=f){

        if(t->p->p==f){

            rot(t);

        }

        else{

            t->d()==t->p->d()? (rot(t->p),rot(t)):(rot(t),rot(t));

        }

    }

    t->pushUp();

}



Node *select(int k){

    for(Node *t=root;;){

        t->pushDown();

        int c=t->ch[0]->size;

        if(k==c) {

            return t;

        }

        if(k>c) {

            k-=c+1,t=t->ch[1];

        }

        else{ 

            t=t->ch[0];

        }

    }

}



Node*&get(int l,int r){ //[l,r)

    Node *L=select(l-1);

    Node *R=select(r);

    splay(L);

    splay(R,L);

    return R->ch[0];

}



int n,m;



int main()

{

    while(cin>>n>>m)

    {

        C=mem;

        for(int i=1;i<=n;++i){

            scanf("%d",&a[i]);

        }

        root=build(0,n+2);

        root->p=null;

        char str[3];int l,r;

        for(int i=0;i<m;++i){

            scanf("%s%d%d",str,&l,&r);

            if(strcmp(str,"Q")==0){

                Node*&t=get(l,r+1);

                printf("%d\n",t->mx);

            }

            else{

                Node*&t=get(l,l+1);

                t->setIt(r);

            }

        }    

    }

    return 0;

}

 

你可能感兴趣的:(play)