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