SplayTree指针模板 & LinkCutTree指针模板

qwq我为了找个指针版的好难啊,调试的时候,指针教我做人(手动再见)。



没写太多的讲解,如果有问题可以评论里问。

借鉴了akb的短快涨的代码,写的尽量短了,qwq我觉得把splay写两行也是没谁了。这是BZOJ3224的代码。splay实现treap的功能

//QWsin
//splay 版 
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100000+10;
const int INF=1<<30;
inline int read()
{
    int ret=0,ok=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')ok=-1;ch=getchar();}
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
    return ret*ok;
}

struct Node{
    int sz,v;
    Node *fa,*ch[2]; 
    Node(int v=0):v(v){sz=1;fa=ch[0]=ch[1]=NULL;}
    inline int cmp(int x){return x==v?-1:x>v;}
    inline void up(){
        sz=1;
        if(ch[0]!=NULL) sz+=ch[0]->sz;
        if(ch[1]!=NULL) sz+=ch[1]->sz;
    }
}*pool[maxn*2];

int top=0,n;
inline void init(){for(int i=0;i<maxn;++i) pool[i]=new Node();  }
inline void newnode(Node* &p,int v,Node *fa){
    p=pool[top++];*p=Node(v);p->fa=fa;
}
inline void del(Node* &p){pool[--top]=p;p=NULL;}

struct SplayTree{

    Node *root;

    inline int pd(Node *p){return p->fa->ch[1]==p;}

    inline void rotate(Node* p)
    {
        int c=pd(p)^1;Node *t=p->fa;
        t->ch[c^1]=p->ch[c];
        if(p->ch[c])p->ch[c]->fa=t;
        if((p->fa=t->fa)!=NULL) p->fa->ch[p->fa->ch[1]==t]=p;
        t->fa=p;p->ch[c]=t;t->up();p->up();
        if(p->fa==NULL) root=p;
    }

    inline void splay(Node* p,Node *FA)
    {
        for(;p->fa!=FA;rotate(p))
            if(p->fa->fa!=FA) rotate(pd(p)==pd(p->fa)?p->fa:p);
    }

    void insert(Node* p,int val)
    {
        if(root==NULL){newnode(root,val,NULL);return ;}
        Node *fa=NULL;
        while(p!=NULL) fa=p,p=p->ch[val > p->v];
        newnode(p,val,fa);fa->ch[val>fa->v]=p;
        for(fa=p->fa;fa!=NULL;fa=fa->fa) 
            fa->up();
        splay(p,NULL);
    }

    inline Node* find(Node *p,int val)
    {
        while(p!=NULL) {
            int tcmp=p->cmp(val);
            if(tcmp==-1) return p;
            p=p->ch[tcmp];
        }
        return NULL;
    }

    Node* MAX(Node* p){
        if(p==NULL) return NULL;
        while(p->ch[1]!=NULL) p=p->ch[1];
        return p;
    }

    //要求是两颗子树的根,不一定非空 
    Node* merge(Node* a,Node* b)
    {
        if(!b) return a;
        if(!a) return b;
        Node *t=MAX(a);
        splay(t,NULL);
        t->ch[1]=b;b->fa=t;t->up();
        return t;
    }

    void remove(Node* p,int val)
    {
        Node* pos=find(root,val);
        splay(pos,NULL);
        pos=root;del(root);
        root=merge(pos->ch[0],pos->ch[1]);
        if(root!=NULL)root->fa=NULL;//这里不改会T的 
    }

    inline int rank(Node* p,int val)
    {
        int ret=1;
        while(p!=NULL){
            int tcmp=val > p->v,d=p->ch[0]?p->ch[0]->sz:0;
            if(tcmp) ret+=d+1; p=p->ch[tcmp];
        }
        return ret;
    }

    inline int kth(Node* p,int k)
    {
        while(p!=NULL){
            int d=p->ch[0]?p->ch[0]->sz:0;
            if(k==d+1) return p->v;
            if(k<d+1) p=p->ch[0];
            else k-=d+1,p=p->ch[1];
        }
        return -1;
    }

    inline int Pre(Node* p,int val)
    {
        int ret=-INF;
        while(p!=NULL){
            int tcmp=val > p->v;
            if(tcmp) ret=max(ret,p->v);
            p=p->ch[tcmp];
        }
        return ret;
    }

    inline int Sub(Node* p,int val)
    {
        int ret=INF;
        while(p!=NULL){
            int tcmp=val < p->v;
            if(tcmp) ret=min(ret,p->v);
            p=p->ch[tcmp^1];
        }
        return ret;
    }

    inline void insert(int x){insert(root,x);}
    inline void remove(int x){remove(root,x);}
    inline int rank(int x){return rank(root,x);}
    inline int kth(int x){return kth(root,x);}
    inline int Pre(int x){return Pre(root,x);}
    inline int Sub(int x){return Sub(root,x);}
}splay;

char s[maxn];int _p;
inline void printf(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(!x) {putchar('0');return ;}
    for(_p=0;x;x/=10) s[++_p]=x%10+'0';
    for(int i=_p;i>=1;--i) putchar(s[i]);
    putchar('\n');
}

int main()
{
    freopen("std.in","r",stdin);
    int op,x;cin>>n;init();
    while(n--)
    {
        op=read();x=read();
        if(op==1) splay.insert(x);
        else if(op==2) splay.remove(x);
        else if(op==3) printf(splay.rank(x));
        else if(op==4) printf(splay.kth(x));
        else if(op==5) printf(splay.Pre(x));
        else printf(splay.Sub(x));
    }
    return 0;
}

渐渐发现splay是一棵,会旋转的线段树!话说节点个数严格n个来着。顿时感觉线段树活了起来(雾)。下面这是codevs线段树练习3的代码。(不过splay好像比线段树跑得慢得多)。

//QWsin
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=200000+10;

int a[maxn];

struct Node{
    int sz,v,add;ll sum;
    Node *fa,*ch[2];
    Node(){}
    inline void up(){
        sz=1+ch[0]->sz+ch[1]->sz;
        sum=v+ch[0]->sum+ch[1]->sum;
    }
    inline void push(){
        if(!add)return ;
        ch[0]->sum+=1ll*ch[0]->sz*add,ch[0]->add+=add,ch[0]->v+=add;
        ch[1]->sum+=1ll*ch[1]->sz*add,ch[1]->add+=add,ch[1]->v+=add;
        add=0;
    }
}*root,*pool[maxn];

Node *null;

struct SplayTree{

    int top;
    inline void clear(){top=1;}
    inline void newnode(Node* &p,int v,Node* fa){
        p=pool[top++];p->sz=1;
        p->v=p->sum=v;p->add=0;
        p->fa=fa;p->ch[0]=p->ch[1]=null;
    }

    //如果p是p->fa的右儿子返回1 
    inline int pd(Node* p){return p->fa->ch[1]==p;}

    inline void rotate(Node* p)
    {
        int c=pd(p)^1;Node *f=p->fa;
        f->ch[c^1]=p->ch[c];p->ch[c]->fa=f;
        if((p->fa=f->fa)!=null) p->fa->ch[p->fa->ch[1]==f]=p;
        f->fa=p;p->ch[c]=f;f->up();p->up();
        if(p->fa==null) root=p;//记得换根 
    }

    inline void splay(Node* p,Node *FA)
    {
        for(p->push();p->fa!=FA;rotate(p))
            if(p->fa->fa!=FA) rotate(pd(p)==pd(p->fa)?p:p->fa);
    }

    inline void find_rot(int k,Node* FA)//找到并旋转为FA的儿子
    {
        Node* p=root;p->push();
        while(p!=null)
        {
            if(k == p->ch[0]->sz +1) break;
            if(k<=p->ch[0]->sz) p=p->ch[0];
            else k-=p->ch[0]->sz+1,p=p->ch[1];
            p->push();
        }
        if(p==null) return ;
        splay(p,FA);
    }

    //------以上为常用函数

    #define mid ((l+r)>>1)
    inline void build(Node* &p,int l,int r,Node *fa)
    {
        if(r<l) return ;
        newnode(p,a[mid],fa);
        build(p->ch[0],l,mid-1,p);
        build(p->ch[1],mid+1,r,p);p->up();
    }
    #undef mid

    inline void init(){
        for(int i=0;i<maxn;++i) pool[i]=new Node();
        null=new Node();
        null->v=null->sum=null->sz=0;null->add=0;
        null->ch[0]=null->ch[1]=null->fa=NULL;

        int n;cin>>n;
        for(int i=1;i<=n;++i) scanf("%d",a+i);
        newnode(root,0,null);//为了防止RE需要建立虚节点 
        newnode(root->ch[1],0,root);root->sz=2;
        build(root->ch[1]->ch[0],1,n,root->ch[1]);
        root->ch[1]->up();root->up();
    }

    inline void updata(int l,int r,int val)
    {
        find_rot(l,null);find_rot(r+2,root);//因为有两个虚点所以rank要+1 
        Node *t=root->ch[1]->ch[0];
        t->v+=val;t->add+=val;t->sum+=1ll*t->sz*val;
    }

    inline ll query(int l,int r)
    {
        find_rot(l,null);find_rot(r+2,root);
        return root->ch[1]->ch[0]->sum;
    }
    //根据题目性质 上面为类似线段树的东西 
}spt;

int main()
{
    spt.init();
    int Q,op,a,b,c;cin>>Q;
    while(Q--)
    {
        scanf("%d",&op);
        if(op==1) {
            scanf("%d%d%d",&a,&b,&c);
            spt.updata(a,b,c);
        }
        else{
            scanf("%d%d",&a,&b);
            printf("%lld\n",spt.query(a,b));
        }
    }
    return 0;
}

所以splay真的很强大。要是快一点的话简直无敌了。

初衷是为了学习lct才复习的splay,下面是lct的模板,BZOJ2002弹飞绵羊,注意splay和rotate函数和写裸的splay的差别比较大,主要分清楚辅助树的根和原来树的根这两个概念,,另外zzq学长说版子一定要找对,他第一份lct调了三天,当时他好像把splay旋断了,旋出环了qwq,幸好我调了两个小时就过了qwq主要还是splay没什么问题了,借鉴了一下这位的代码。代码戳这里。因为指针的lct实在太难找了qwq,找了一份模拟链表的。

//QWsin
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=200000+10;
inline int read()
{
    int ret=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
    return ret;
}

char s[20];int _p;
inline void output(int x)
{
    if(!x){putchar('0');return ;}
    for(_p=0;x;x/=10) s[++_p]=x%10+'0';
    for(int i=_p;i>=1;--i) putchar(s[i]);
    putchar('\n');
}

struct Node {
    int sz,rev;
    Node *fa,*ch[2];
    Node() {sz=1;rev=0;fa=ch[0]=ch[1]=NULL;}
    inline void up() {
        sz=1;
        if(ch[0]) sz+=ch[0]->sz;
        if(ch[1]) sz+=ch[1]->sz;
    }
    inline void push() {
        if(!rev) return ;
        swap(ch[0],ch[1]);rev=0;
        if(ch[0])ch[0]->rev^=1;
        if(ch[1])ch[1]->rev^=1;
    }
}*pool[maxn*2],*tmp[maxn];

int top=0;
inline void init_pool() {
    for(int i=0; i<maxn; ++i)pool[i]=new Node();
}
inline void newnode(Node* &p,Node *fa) {p=pool[top++];*p=Node();p->fa=fa;}
inline void del(Node* &p) {pool[--top]=p;p=NULL;}

int to[maxn],n;
struct LinkCutTree {

    Node *node[maxn];

    inline void init(int n) {for(int i=1; i<=n; ++i) newnode(node[i],NULL);}

    inline int is_root(Node* p) {
        return !(p->fa)||(p->fa->ch[0]!=p&&p->fa->ch[1]!=p);
    }
    inline int pd(Node* p) {return p->fa->ch[1]==p;}
    inline void rotate(Node* p) {
        int c=pd(p)^1;Node *t=p->fa;
        t->ch[c^1]=p->ch[c];
        if(p->ch[c]) p->ch[c]->fa=t;
        p->fa=t->fa;
        if(!is_root(t)) p->fa->ch[pd(t)]=p;
        t->fa=p;p->ch[c]=t;t->up();p->up();
    }
    inline void splay(Node* p) {
        int pos=0;
        for(Node *t=p;; t=t->fa) {
            tmp[++pos]=t;
            if(is_root(t)) break;
        }
        for(; pos>=1; --pos) tmp[pos]->push();

        for(; !is_root(p); rotate(p))
            if(!is_root(p->fa)) rotate(pd(p)==pd(p->fa)?p->fa:p);
        p->up();
    }

    inline void access(Node* p) {
        for(Node* pre=NULL; p; pre=p,p=p->fa)
            splay(p),p->ch[1]=pre,p->up();
    }
    inline void make_root(Node* p) {access(p);splay(p);p->rev^=1;}
    inline void cut(Node *x,Node *y) {
        make_root(x);access(y);splay(y);
        x->fa=y->ch[0]=NULL;y->up();
    }
    //因为link之后x不是y的splay上的儿子所以y不up
    inline void link(Node *x,Node *y) {make_root(x);x->fa=y;}

    inline void link(int x,int y) {node[x]->fa=node[y];}
    inline void op1(int x) {
        make_root(node[n+1]);
        access(node[x]);
        splay(node[x]);
        output(node[x]->ch[0]->sz);
    }
    inline void op2(int x,int y) {
        cut(node[x],node[min(x+to[x],n+1)]);
        to[x]=y;
        link(node[x],node[min(x+to[x],n+1)]);
    }
} lct;

int main() {
    cin>>n;
    init_pool();
    lct.init(n+1);

    for(int i=1; i<=n; ++i) {
        to[i]=read();
        lct.link(i,min(i+to[i],n+1));
    }

    int Q,op,x,y;
    cin>>Q;
    while(Q--) {
        scanf("%d",&op);
        if(op==1)  lct.op1(read()+1);
        else {
            x=read();y=read();
            lct.op2(++x,y);
        }
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值