事实证明这不是一道太难的题,只要能把伸展树(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操作效果可能一样,所以用标记就快多啦。
差不多就是这些,先写到这儿吧。写伸展树需要细心。
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->l = p->r; p->r = t;
34 }
35 void rot_left(NP p) {
36 NP y = p->r;
37 p->r = y->l;
38 if(y->l) y->l->f = p;
39 y->l = p;
40 y->f = p->f;
41 if(p->f) {
42 if(p == p->f->l)
43 p->f->l = y;
44 else if(p == p->f->r)
45 p->f->r = y;
46 }
47 else {
48 root = y;
49 }
50 p->f = y;
51 calc_size(p);
52 calc_size(y);
53 }
54 void rot_right(NP p) {
55 NP y = p->l;
56 p->l = y->r;
57 if(y->r) y->r->f = p;
58 y->r = p;
59 y->f = p->f;
60 if(p->f) {
61 if(p == p->f->l)
62 p->f->l = y;
63 else if(p == p->f->r)
64 p->f->r = y;
65 }
66 else {
67 root = y;
68 }
69 p->f = 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->l && p == fa->l) {
93 rot_right(gf);
94 rot_right(fa);
95 }
96 else if(fa == gf->r && p == fa->r) {
97 rot_left(gf);
98 rot_left(fa);
99 }
100 else if(fa == gf->l && p == fa->r) {
101 rot_left(fa);
102 rot_right(gf);
103 }
104 else if(fa == gf->r && 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->l == 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