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 }
然后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 }
然后,,因为要复习了,暂时就放放了。。
以上是关于ACM之路(20)—— Splay初探的主要内容,如果未能解决你的问题,请参考以下文章