事实证明这不是一道太难的题,只要能把伸展树(Splay Tree)写好,并且能在上面做一些拓展的操作。

之前想法比较简单,想建个笛卡尔树(Cartesian Tree),由笛卡尔树的性质来保证整棵树的有序性(左儿子的下标小,右儿子的下标大,父亲节点的关键字大于儿子节点的关键字)。后来越想越复杂,因为reverse操作在笛卡尔树上面做起来很麻烦,时间效率肯定暴低,所以放弃了使用笛卡尔树,还是老老实实写伸展树。

伸展树的问题在于如何在整棵树上很快地找到最小值,答案是预处理。先把序列读入进来,然后排序预处理一下,复杂度为O(nlogn),然后用伸展树进行操作。而伸展树的splay操作复杂度也是O(nlogn),reverse操作可以由一个简单的标记解决,认真分析一下,发现问题可以得到完美的解决。

几个要点需要注意:

1.预处理

想到用伸展树之后还是卡了一会儿,没想到预处理,这个比较失败。 

2.reverse操作

reverse操作可以直接标记在一个节点上,表示以这个节点为根的子树需要reverse。而对一棵树reverse就是交换左右儿子,然后把自身的标记抹掉,并传递给儿子节点。 注意在将一个节点splay到根节点的时候,给它的左儿子打上reverse标记的时候不要直接赋值,而是要用异或操作,因为它的左儿子可能已经有了一个reverse标记。

3.rotate操作

在进行rotate操作的时候,需要保证需要旋转的节点reverse标记已经被抹除,否则会出错。而相关节点的儿子节点,由于他们之间的相对关系以及各个子树的结构并不会受到rotate操作的影响,所以只需要将reverse标记传到子树上就可以了。因为多次reverse操作效果可能一样,所以用标记就快多啦。

差不多就是这些,先写到这儿吧。写伸展树需要细心。

ZOJ 2985 Robotic Sort
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define DEBUG 0
  5 
  6 const int MaxN = 100010;
  7 
  8 struct Node {
  9     int size, reverse, remove;
 10     struct Node *l, *r, *f;
 11     Node()
 12         :size(0), reverse(0), remove(0), l(NULL), r(NULL), f(NULL)
 13     {}
 14 }node[MaxN];
 15 
 16 typedef struct Node *NP;
 17 
 18 struct SplayTree {
 19     NP root;
 20     void calc_size(NP p) {
 21         p->size = 0;
 22         if(!p->remove) p->size++;
 23         if(p->l) p->size += p->l->size;
 24         if(p->r) p->size += p->r->size;
 25     }
 26     void clean_reverse(NP p) {
 27         if(p->reverse == 0)
 28             return;
 29         p->reverse = 0;
 30         if(p->l) p->l->reverse ^= 1;
 31         if(p->r) p->r->reverse ^= 1;
 32         NP t;
 33         t = p->l; p->= p->r; p->= t;
 34     }
 35     void rot_left(NP p) {
 36         NP y = p->r;
 37         p->= y->l;
 38         if(y->l) y->l->= p;
 39         y->= p;
 40         y->= p->f;
 41         if(p->f) {
 42             if(p == p->f->l)
 43                 p->f->= y;
 44             else if(p == p->f->r)
 45                 p->f->= y;
 46         }
 47         else {
 48             root = y;
 49         }
 50         p->= y;
 51         calc_size(p);
 52         calc_size(y);
 53     }
 54     void rot_right(NP p) {
 55         NP y = p->l;
 56         p->= y->r;
 57         if(y->r) y->r->= p;
 58         y->= p;
 59         y->= p->f;
 60         if(p->f) {
 61             if(p == p->f->l)
 62                 p->f->= y;
 63             else if(p == p->f->r)
 64                 p->f->= y;
 65         }
 66         else {
 67             root = y;
 68         }
 69         p->= y;
 70         calc_size(p);
 71         calc_size(y);
 72     }
 73     void splay(const NP &p) {
 74         if(p == root)
 75             return;
 76         else {
 77             NP fa = p->f;
 78             if(fa == root) {
 79                 clean_reverse(fa);
 80                 clean_reverse(p);
 81                 if(p == fa->l)
 82                     rot_right(root);
 83                 else
 84                     rot_left(root);
 85                 return;
 86             }
 87             else {
 88                 NP gf = fa->f;
 89                 clean_reverse(gf);
 90                 clean_reverse(fa);
 91                 clean_reverse(p);
 92                 if(fa == gf->&& p == fa->l) {
 93                     rot_right(gf);
 94                     rot_right(fa);
 95                 }
 96                 else if(fa == gf->&& p == fa->r) {
 97                     rot_left(gf);
 98                     rot_left(fa);
 99                 }
100                 else if(fa == gf->&& p == fa->r) {
101                     rot_left(fa);
102                     rot_right(gf);
103                 }
104                 else if(fa == gf->&& p == fa->l) {
105                     rot_right(fa);
106                     rot_left(gf);
107                 }
108             }
109         }
110         splay(p);
111     }
112 }tree;
113 
114 int N, mtp;
115 int num[MaxN], buf[MaxN], idxn[MaxN];
116 NP idx[MaxN];
117 
118 int cmp(const void *a, const void * b) {
119     int va = *(int *)a;
120     int vb = *(int *)b;
121     if(num[va] != num[vb])
122         return num[va] - num[vb];
123     return va-vb;
124 }
125 
126 int do_reverse(NP t) {
127     tree.splay(t);
128     t->remove = 1;
129     if(t->== NULL) {
130         return 0;
131     }
132     t->l->reverse ^= 1;
133     return t->l->size;
134 }
135 
136 void work() {
137     for(int i = 0; i < N; ++i) {
138         buf[i] = i;
139     }
140     qsort(buf, N, sizeof(int), cmp);
141 #if DEBUG
142     for(int i = 0; i < N; ++i) {
143         printf("%d%c", num[i], i+1==N?'\n':' ');
144     }
145     for(int i = 0; i < N; ++i) {
146         printf("%d%c", buf[i], i+1==N?'\n':' ');
147     }
148 #endif
149     mtp = 0;
150     for(int i = 0; i < N; ++i) {
151         node[i] = Node();
152         node[i].size = i + 1;
153         if(i)
154             node[i].l = node + i - 1;
155         if(i + 1 < N)
156             node[i].f = node + i + 1;
157     }
158     tree.root = node + N - 1;
159 #if DEBUG
160     printf("ans = ");
161 #endif
162     for(int i = 0; i < N; ++i) {
163         printf("%d%c", do_reverse(node + buf[i]) + i + 1, i+1==N?'\n':' ');
164     }
165 }
166 
167 int main() {
168 #if DEBUG
169     freopen("test.in""r", stdin);
170     freopen("test.out""w", stdout);
171 #endif
172     while(scanf("%d"&N) && N) {
173         for(int i = 0; i < N; ++i) {
174             scanf("%d", num+i);
175         }
176         work();
177     }
178     return 0;
179 }
180