Splay

Posted yijiull

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Splay相关的知识,希望对你有一定的参考价值。

  1 // UVa11922 Permutation Transformer
  2 // Rujia Liu
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<vector>
  6 using namespace std;
  7 
  8 struct Node {
  9   Node *ch[2];
 10   int s;
 11   int flip;
 12   int v;
 13   int cmp(int k) const {
 14     int d = k - ch[0]->s;
 15     if(d == 1) return -1;
 16     return d <= 0 ? 0 : 1;
 17   }
 18   void maintain() {
 19     s = ch[0]->s + ch[1]->s + 1;
 20   }
 21   void pushdown() {
 22     if(flip) {
 23       flip = 0;
 24       swap(ch[0], ch[1]);
 25       ch[0]->flip = !ch[0]->flip;
 26       ch[1]->flip = !ch[1]->flip;
 27     }
 28   }
 29 };
 30 
 31 Node *null = new Node();
 32 
 33 void rotate(Node* &o, int d) {
 34   Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
 35   o->maintain(); k->maintain(); o = k; 
 36 }
 37 
 38 void splay(Node* &o, int k) {
 39   o->pushdown();
 40   int d = o->cmp(k);
 41   if(d == 1) k -= o->ch[0]->s + 1;
 42   if(d != -1) {
 43     Node* p = o->ch[d];
 44     p->pushdown();
 45     int d2 = p->cmp(k);
 46     int k2 = (d2 == 0 ? k : k - p->ch[0]->s - 1);
 47     if(d2 != -1) {
 48       splay(p->ch[d2], k2);
 49       if(d == d2) rotate(o, d^1); else rotate(o->ch[d], d);
 50     }
 51     rotate(o, d^1);
 52   }
 53 }
 54 
 55 // 合并left和right。假定left的所有元素比right小。注意right可以是null,但left不可以
 56 Node* merge(Node* left, Node* right) {
 57   splay(left, left->s);
 58   left->ch[1] = right;
 59   left->maintain();
 60   return left;
 61 }
 62 
 63 // 把o的前k小结点放在left里,其他的放在right里。1<=k<=o->s。当k=o->s时,right=null
 64 void split(Node* o, int k, Node* &left, Node* &right) {
 65   splay(o, k);
 66   left = o;
 67   right = o->ch[1];
 68   o->ch[1] = null;
 69   left->maintain();
 70 }
 71 
 72 const int maxn = 100000 + 10;
 73 struct SplaySequence {
 74   int n;
 75   Node seq[maxn];
 76   Node *root;
 77 
 78   Node* build(int sz) {
 79     if(!sz) return null;
 80     Node* L = build(sz/2);
 81     Node* o = &seq[++n];
 82     o->v = n; // 节点编号
 83     o->ch[0] = L;
 84     o->ch[1] = build(sz - sz/2 - 1);
 85     o->flip = o->s = 0;
 86     o->maintain();
 87     return o;
 88   }
 89 
 90   void init(int sz) {
 91     n = 0;
 92     null->s = 0;
 93     root = build(sz);
 94   }
 95 };
 96 
 97 vector<int> ans;
 98 void print(Node* o) {
 99   if(o != null) {
100     o->pushdown();
101     print(o->ch[0]);
102     ans.push_back(o->v);
103     print(o->ch[1]);
104   }
105 }
106 
107 void debug(Node* o) {
108   if(o != null) {
109     o->pushdown();
110     debug(o->ch[0]);
111     printf("%d ", o->v-1);
112     debug(o->ch[1]);
113   }
114 }
115 
116 SplaySequence ss;
117 int main()
118 {
119   int n, m;
120   scanf("%d%d", &n, &m);
121   ss.init(n+1); // 最前面有一个虚拟结点
122 
123   while (m--) {
124     int a, b;
125     scanf("%d%d", &a, &b);
126     Node *left, *mid, *right, *o;
127     split(ss.root, a, left, o); // 如果没有虚拟结点,a将改成a-1,违反split的限制
128     split(o, b-a+1, mid, right);
129     mid->flip ^= 1;
130     ss.root = merge(merge(left, right), mid);
131   }
132 
133   print(ss.root);
134   for(int i = 1; i < ans.size(); i++)
135     printf("%d\n", ans[i]-1); // 节点编号减1才是本题的元素值
136 
137   return 0;
138 }

 

以上是关于Splay的主要内容,如果未能解决你的问题,请参考以下文章

UESTC2021暑假前集训(splay树)

SPLAY or SPALY ?

模板Splay

文艺平衡树(splay模板)

bzoj2733 永无乡 splay树的启发式合并

●Splay的一些题