ACM之路(20)—— Splay初探

Posted Storm_Spirit

tags:

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

  由于数据结构上老师讲了AVL树的rotate,然后去学了一下treap和Splay,这些数据结构还真是神奇啊!

  treap暂时只知道名次树的作用(就是一段动态变化的有序数列,找第K大的元素,用set显然是O(n)的。。)。

  好,正式介绍SplayTree这个神奇的数据结构:暂时的理解是,用于解决一些线段树解决不了的区间问题,比方说区间翻转,区间删除并插入等等(似乎分块也可以解决一些xjbg的区间问题)。。然后,Splay还可以解决掉LCT的问题(暂时还不会,,下次继续学习)。

  然后就愉快地掏出模板吧(直接修改了铭神的模板)。。仓鼠挂的平衡树

  G题,区间翻转+区间切割的。直接掏出模板套上去就是了:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 #define tochange (root->ch[1]->ch[0])
  5 using namespace std;
  6 const int N = 300000 + 100;
  7 struct node *nill, *root;
  8 struct node {
  9     int val;
 10     int sz;
 11     bool rev;
 12     node *ch[2],*fa;
 13     void init(int v = 0)
 14     {
 15         ch[0] = ch[1] = fa = nill;
 16         val = v;
 17         sz = 1;
 18     }
 19     void up() {
 20         if (this==nill) return ;
 21         sz = ch[0]->sz + ch[1]->sz + 1;
 22     }
 23     void down() {
 24         if (this==nill) return ;
 25         if(rev)
 26         {
 27             rev = false;
 28             ch[0]->rev ^= 1;
 29             ch[1]->rev ^= 1;
 30             swap(ch[0], ch[1]);
 31         }
 32     }
 33     bool d() {
 34         return fa->ch[1]==this;
 35     }
 36     void reverse() {
 37         rev ^= 1;
 38         std::swap(ch[0],ch[1]);
 39     }
 40     void setc(node *o,int c) {
 41         ch[c] = o;
 42         o->fa = this;
 43         up();
 44     }
 45     void rot() {
 46         int c = d(),cc = fa->d();
 47         node *z = fa->fa;
 48         node *tmp = fa;
 49         fa->setc(ch[c^1],c);
 50         setc(tmp,c^1);
 51         if(z!=nill) z->setc(this,cc);
 52         else fa = z;  // 这里的if-else不加也行,因为对于nill来说无论儿子是谁都无所谓,
 53                       // 并且,setc时的up对nill无效
 54     }
 55     void D() {
 56         if (this==nill) return ;
 57         fa->D();
 58         down();
 59     }
 60     void splay(node *aim = nill) {
 61         D();
 62         while (fa!=aim) {
 63             if (fa->fa!=aim) {
 64                 d()==fa->d() ? fa->rot() : rot();
 65             }
 66             rot();
 67         }
 68         if(aim == nill) root = this;
 69     }
 70 }memo[N], *bat;
 71 
 72 node* findK(node* o, int k)
 73 {
 74     while(1)
 75     {
 76         o->down();
 77         if(o->ch[0]->sz + 1 == k)
 78         {
 79             return o;
 80         }
 81         if(o->ch[0]->sz >= k) o = o->ch[0];
 82         else
 83         {
 84             k -= o->ch[0]->sz + 1;
 85             o = o->ch[1];
 86         }
 87     }
 88 }
 89 
 90 node* get_min(node* o)
 91 {
 92     /*while(o->ch[0] != nill)
 93     {
 94         o->down();
 95         o = o->ch[0];
 96     }
 97     return o;*/
 98     // 上面写法错了,为什么?
 99     // -因为可能o本来是没有左边的儿子的,一交换以后就有了,所以要先down().
100     o->down();
101     while(o->ch[0] != nill)
102     {
103         o = o->ch[0];
104         o->down();
105     }
106     return o;
107 }
108 
109 void Reverse(int a,int b)
110 {
111     node* x = findK(root,a);
112     node* y = findK(root,b+2);
113     x->splay();
114     y->splay(root);
115     tochange->rev ^= 1;
116 }
117 
118 void Cut(int a,int b,int c)
119 {
120     node* x = findK(root, a);
121     node* y = findK(root, b+2);
122     x->splay();
123     y->splay(root);
124     node* temp = tochange;
125     y->setc(nill, 0);
126     node* z = findK(root, c+1);
127     z->splay();
128     z = get_min(root->ch[1]);
129     z->splay(root);
130     root->ch[1]->setc(temp, 0);
131 }
132 
133 int n,m;
134 node* newNode(int val = 0)
135 {
136     node* o = bat ++;
137     o->init(val);
138     return o;
139 }
140 void init()
141 {
142     bat = memo;
143     nill = newNode(); nill->sz = 0;
144     root = newNode(); root->fa = nill;
145     node* p = newNode(), *p2 = nill;
146     root->setc(p, 1);
147     p = nill;
148     for(int i=1;i<=n;i++)
149     {
150         p2 = newNode(i);
151         p2->setc(p, 0);
152         p = p2;
153     }
154     root->ch[1]->setc(p, 0);
155 }
156 
157 int cnt = 0;
158 void print(node* o)
159 {
160     if(o == nill) return ;
161     o->down();
162     print(o->ch[0]);
163     if(cnt >= 1 && cnt <= n)
164     {
165         if(cnt > 1) printf(" ");
166         printf("%d",o->val);
167     }
168     cnt++;
169     print(o->ch[1]);
170 }
171 
172 int main()
173 {
174     while(scanf("%d%d",&n,&m) == 2)
175     {
176         if(n == -1 && m == -1) break;
177         init();
178 
179         char s[10];
180         while(m--)
181         {
182             scanf("%s",s);
183             if(s[0] == \'F\')
184             {
185                 int a,b;scanf("%d%d",&a,&b);
186                 Reverse(a,b);
187             }
188             else
189             {
190                 int a,b,c;
191                 scanf("%d%d%d",&a,&b,&c);
192                 Cut(a,b,c);
193             }
194         }
195         cnt = 0;
196         print(root);
197         puts("");
198     }
199 }
Splay区间翻转+区间切割

 

  然后A题,可以直接map写,然后弹出最大最小就可以了。为了练手Splay,特地用Splay写了一遍(惊喜的是时间比map的要短= =)。

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 #define tochange (root->ch[1]->ch[0])
  5 using namespace std;
  6 const int N = 300000 + 100;
  7 struct node *nill, *root;
  8 struct node {
  9     int val, key;
 10     int sz;
 11     bool rev;
 12     node *ch[2],*fa;
 13     void init(int v,int p)
 14     {
 15         ch[0] = ch[1] = fa = nill;
 16         val = v;
 17         key = p;
 18         sz = 1;
 19     }
 20     void up() {
 21         if (this==nill) return ;
 22         sz = ch[0]->sz + ch[1]->sz + 1;
 23     }
 24     void down() {
 25         if (this==nill) return ;
 26         if(rev)
 27         {
 28             rev = false;
 29             ch[0]->rev ^= 1;
 30             ch[1]->rev ^= 1;
 31             swap(ch[0], ch[1]);
 32         }
 33     }
 34     bool d() {
 35         return fa->ch[1]==this;
 36     }
 37     void reverse() {
 38         rev ^= 1;
 39         std::swap(ch[0],ch[1]);
 40     }
 41     void setc(node *o,int c) {
 42         ch[c] = o;
 43         o->fa = this;
 44         up();
 45     }
 46     void rot() {
 47         int c = d(),cc = fa->d();
 48         node *z = fa->fa;
 49         node *tmp = fa;
 50         fa->setc(ch[c^1],c);
 51         setc(tmp,c^1);
 52         if(z!=nill) z->setc(this,cc);
 53         else fa = z;
 54     }
 55     void D() {
 56         if (this==nill) return ;
 57         fa->D();
 58         down();
 59     }
 60     void splay(node *aim = nill) {
 61         D();
 62         while (fa!=aim) {
 63             if (fa->fa!=aim) {
 64                 d()==fa->d() ? fa->rot() : rot();
 65             }
 66             rot();
 67         }
 68         if(aim == nill) root = this;
 69     }
 70 }memo[N], *bat;
 71 
 72 node* newNode()
 73 {
 74     node* o = bat ++;
 75     return o;
 76 }
 77 void init()
 78 {
 79     bat = memo;
 80     nill = newNode(); nill->sz = 0;
 81     root = nill;
 82 }
 83 
 84 void _insert(node* o, node* p)
 85 {
 86     if(p->key < o->key)
 87     {
 88         if(o->ch[0] == nill) {o->setc(p, 0);return ;}
 89         else _insert(o->ch[0], p);
 90     }
 91     else if(p->key > o->key)
 92     {
 93         if(o->ch[1] == nill) {o->setc(p, 1);return ;}
 94         else _insert(o->ch[1], p);
 95     }
 96 }
 97 void insert(int val,int key)
 98 {
 99     node* p = newNode();
100     p->init(val, key);
101     if(root == nill) root = p;
102     else _insert(root, p);
103 }
104 
105 node* get_max_or_min(node* o, int op)
106 {
107     //o->down();
108     while(o->ch[op] != nill)
109     {
110         o = o->ch[op];
111         //o->down();
112     }
113     return o;
114 }
115 // 1->pop_max, 0->pop_min
116 void pop_max_or_min(int op)
117 {
118     if(root == nill) {printf("0\\n");return;}
119     node* p = get_max_or_min(root, op);
120     p->splay(nill);
121     printf("%d\\n",p->val);
122     root = p->ch[op^1];
123     root->fa = nill;
124 }
125 
126 int main()
127 {
128     init();
129     int n;
130     while(scanf("%d",&n) == 1 && n)
131     {
132         if(n == 1)
133         {
134             int val, key;scanf("%d%d",&val,&key);
135             insert(val,key);
136         }
137         else if(n == 2) pop_max_or_min(1);
138         else pop_max_or_min(0);
139     }
140     return 0;
141 }
Splay维护最大或最小key的节点

  

  然后,,因为要复习了,暂时就放放了。。

以上是关于ACM之路(20)—— Splay初探的主要内容,如果未能解决你的问题,请参考以下文章

初探JSP与LEeclipse

ACM入门之平衡树

cf386(div2)大一狗ACM之路

ACM-ICPC之路

acm之路--母函数 by小宇

HDU 1890 Robotic Sort(splay)