Splay

例题

  题意 :题目定义了四种操作 
  1:表示有一个编号为k的顾客进入等待的队列,他的优先度为p。 
  2:处理优先度最高的顾客,并从等待队列中清除,输出其编号,队列为空输出0。 
  3:处理优先度最低的顾客,并从等待队列中清除,输出其编号,队列为空输出0。 
  0:表示操作结束。

  题目戳这里

CODE

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>

#define sc1(p1) scanf("%d", &p1)
#define sc2(p1, p2) scanf("%d %d", &p1, &p2)
#define sc3(p1, p2, p3) scanf("%d %d %d", &p1, &p2, &p3)

#define pr(p1) printf("%d\n", p1)

#define Getp(x) ((son[fa[x]][1]==(x))?1:0)

using namespace std;

const int maxn = 1000100;
const int oo = 210000000;

int son[maxn][2], fa[maxn], Root;

struct Data {
    int key, id;
    Data(): key(0), id(0){}

    Data(int v, int id1):key(v), id(id1) {}

    void Set(int v, int id1) {*this=Data(v, id1);}
}self[maxn];

void Rotate(int x) {
    int p=Getp(x);
    int f=fa[x];
    if(fa[f]) son[fa[f]][Getp(f)] = x;
    fa[x] = fa[f];
    if(son[x][p^1]) fa[son[x][p^1]] = f;
    son[f][p] = son[x][p^1];
    son[x][p^1] = f, fa[f] = x;
}

void splay(int x) {
    
    while(fa[x]) {
        if(fa[fa[x]] && Getp(fa[x])==Getp(x)) Rotate(fa[x]);
        Rotate(x);
    }
    Root = x;
}
int spac=0;

void work_ins(int key, int num) {
    
    if(!Root) {
        self[Root = ++spac].Set(key, num);
        return ;
    }
    else {
        int x=Root, y=0;
        while(x) {
            y = x;
            x = son[x][key>self[x].key];
        }
        self[x = ++spac].Set(key, num);
        son[y][key>self[y].key]=x, fa[x] = y;
        splay(x);
    }
}

void Remove(int x) {
    
    splay(x);
    
    int a=son[x][0], b=son[x][1];
    
    son[x][0] = son[x][1] = fa[son[x][0]] = fa[son[x][1]] = 0;
    
    if(a==0) { Root = b; return ; }
    if(b==0) { Root = a; return ; }
    
    while(son[a][1]) a=son[a][1];
    
    splay(a), fa[b] = a, son[a][1]=b;
}

int que(int root, int k) {
    int x = root, t;
    while(son[x][k]) x=son[x][k];
    t = self[x].id;
    if(!t) return 0;
    Remove(x);
    return t;
}

int main() {
    
    int ki;
    while(scanf("%d",&ki)!=EOF&&ki) {

        if(ki == 0) return 0;
        if(ki == 1) {
            int a, b; sc2(a, b); work_ins(b, a);
        }
        if(ki == 2) pr(que(Root, 1)); 
        if(ki == 3) pr(que(Root, 0));
    }
    
    return 0;
}

  Splay又称为伸展树,其中最重要的就是splay操作(就是把一个点转到这棵伸展树的根),这样不仅能保持平衡,而且还很方便插入和删除操作,上面这道题简单的强调了splay操作对删除和插入的作用。

 

操作列举

  先给出一道有非常多种操作的题目,(题目戳这里

CODE

 

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>

#define sc1(p1) scanf("%d", &p1)
#define sc2(p1, p2) scanf("%d %d", &p1, &p2)
#define sc3(p1, p2, p3) scanf("%d %d %d", &p1, &p2, &p3)

#define pr(p1) printf("%d\n", p1)

#define Getp(x) ((son[fa[x]][1]==(x))?1:0)

using namespace std;

const int maxn = 2000100;
const int oo = 210000000;

int son[maxn][2], fa[maxn], val[maxn], Root, spac=0;
int st[maxn], A[maxn];

struct Data {
    int siz, mi;
    Data(): siz(0), mi(oo){}
    Data(int siz1, int v):siz(siz1), mi(v){}
    Data operator+(const Data&B) const 
    {
        return Data(siz+B.siz, min(mi, B.mi));
    }
    void add(int v) { mi += v; }
}d[maxn], self[maxn];
struct Mark {
    int rev, ad;
    Mark(): rev(0), ad(0){}
    Mark(int rev1, int ad1):rev(rev1), ad(ad1){}
    void clear(){rev=0, ad=0;}
}mar[maxn];

void apply(int x, const Mark&A);
void pushdown(int x);
void Maintain(int x);
void Rotate(int x);
void splay(int x);
int getnew(int x);
void work_ins(int &root, int p, int v);
void Remove(int &root, int x);
int Merge(int a, int b);
int findkth(int root, int k);
void split(int root, int k, int &a, int &b);
Data query(int &root, int l, int r);
void Revloce(int &root, int l, int r, int t);
void Update(int &root, int l, int r, Mark M);
int build(int l, int r);

void apply(int x, const Mark&A) {
    if(!x) return ;
    if (A.rev) {
        mar[x].rev^=1;
        swap(son[x][0], son[x][1]);
    }
    self[x].add(A.ad), d[x].add(A.ad), val[x]+=A.ad;
    mar[x].ad += A.ad;
}
void pushdown(int x) {
    apply(son[x][0], mar[x]);
    apply(son[x][1], mar[x]);
    mar[x].clear();
}
void Maintain(int x) {
    d[x]=d[son[x][0]]+self[x]+d[son[x][1]];
}
void Rotate(int x) {
    int p=Getp(x);
    int f=fa[x];
    if(fa[f]) son[fa[f]][Getp(f)] = x;
    fa[x] = fa[f];
    if(son[x][p^1]) fa[son[x][p^1]] = f;
    son[f][p] = son[x][p^1];
    son[x][p^1] = f, fa[f] = x;
    Maintain(f);
}
void splay(int x) {
    int to=0, y=x;
    st[++to]=x;
    while(fa[y]) st[++to]=y=fa[y];
    while(to) pushdown(st[to--]);
    while(fa[x]) {
        if(fa[fa[x]] && Getp(fa[x])==Getp(x)) Rotate(fa[x]);
        Rotate(x);
    }
    Maintain(x);
}
int getnew(int x) {
    val[++spac] = x;
    self[spac]=d[spac]=Data(1, x);
    return spac;
}
void work_ins(int &root, int p, int v) {
    int x=getnew(v), a, b;
    split(root, p, a, b), pushdown(a);
    while(son[a][1]) a=son[a][1], pushdown(a);
    splay(a);
    son[a][1]=x, fa[x]=a; Maintain(a);
    root=Merge(a, b);
}
void Remove(int &root, int x) {
    
    splay(x); pushdown(x);
    
    int a=son[x][0], b=son[x][1];
    pushdown(a), pushdown(b);
    son[x][0] = son[x][1] = fa[son[x][0]] = fa[son[x][1]] = 0;
    
    if(a==0) { root = b; return ; }
    if(b==0) { root = a; return ; }
    while(son[a][1]) a=son[a][1], pushdown(a);
    splay(a), root = a, fa[b] = a, son[a][1]=b;
    Maintain(root);
}
int Merge(int a, int b) {
    if(a==0) return b;
    if(b==0) return a;
    splay(a), pushdown(a);
    while(son[a][1]) a=son[a][1], pushdown(a);
    splay(a);
    splay(b), pushdown(b);
    fa[b]=a, son[a][1]=b, Maintain(a);
    return a;
}
int findkth(int root, int k) {
    pushdown(root);
    if(k == 0) return 0;
    if(d[son[root][0]].siz>=k) return findkth(son[root][0], k);
    else k-=d[son[root][0]].siz;
    if(k==1) return root; else --k;
    if(son[root][1])
    return findkth(son[root][1], k);
    else              return root;
}
void split(int root, int k, int &a, int &b) {
    if(k==0) { a=0; b=root; return ; }
    if(k==d[root].siz) { a=root, b=0; return ; }
    a=findkth(root, k);
    splay(a); pushdown(a); b=son[a][1];
    pushdown(a);
    son[a][1]=fa[b]=0;
    Maintain(a);
}
Data query(int &root, int l, int r) {
    int a, b, c, dd;
    split(root, l-1, a, b);
    split(b, r-l+1, c, dd);
    Data ans = d[c];
    b = Merge(c, dd);
    root = Merge(a, b);
    return ans;
}
void Revolce(int &root, int l, int r, int t) {
    t %= (r-l+1);
    if (t==0) return;
    int a, b, c, dd, e, f;
    split(root, l-1, a, b);
    split(b, r-l+1, c, dd);
    split(c, r-l+1-t, e, f);
    c=Merge(f, e);
    b=Merge(c, dd);
    root=Merge(a, b);
}
void Update(int &root, int l, int r, Mark M) {
    int a, b, c, dd;
    split(root, l-1, a, b);
    split(b, r-l+1, c, dd);
    apply(c, M);
    b=Merge(c, dd);
    root=Merge(a, b);
}
int build(int l, int r) {
    if(l> r) return 0;
    if(l==r) return getnew(A[l]);
    int M=(l+r)>>1;
    int x=getnew(A[M]);
    son[x][0]=build(l,M-1);
    son[x][1]=build(M+1,r);
    if(son[x][0]) fa[son[x][0]]=x;
    if(son[x][1]) fa[son[x][1]]=x;
    Maintain(x);
    return x;
}
char s[10];
int main() {
    
    int n, m; sc1(n);
    for (int i=1; i<=n; i++) sc1(A[i]);
    Root = build(1,n);
    sc1(m);
    while (m--) {
        int x,y,z;
        for (int i=0;i<10;++i) s[i]=0;
        scanf("%s", s); sc1(x);
        if (s[0]=='A' || s[3]=='O') sc2(y, z);
        if (s[5]=='S' || s[0]=='I' || s[0]=='M') sc1(y);
        if (s[0]=='A') Update(Root,x,y,Mark(0,z)); else
        if (s[5]=='S') Update(Root,x,y,Mark(1,0)); else
        if (s[3]=='O') Revolce(Root,x,y,z); else
        if (s[0]=='I') work_ins(Root,x,y); else
        if (s[0]=='D') Remove(Root,findkth(Root,x)); else
            printf("%d\n", query(Root,x,y).mi);
    }
    return 0;
}

  有了splay,我们就可以做很多事,合并、分裂、查询一段区间的各种信息,都可以,程序还是非常的简明易懂的,看上面的这个程序就能懂了。

posted @ 2018-08-14 10:27  惜梦园  阅读(166)  评论(0)    收藏  举报