[BZOJ3223] [Tyvj1729] 文艺平衡树 (splay)

Description 

  您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 

Input

  第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数
  接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n

Output 

  输出一行n个数字,表示原始序列经过m次变换后的结果 

Sample Input

5 3
1 3
1 3
1 4

Sample Output

4 3 2 1 5

HINT

  N,M<=100000

Source

  平衡树

Solution

  splay的区间翻转。我的习惯是给序列两端加上虚拟节点,这样查询[l, r]时把l旋到根,把r+2旋到根的右儿子。

  我建树时就建成一条链,因为之后的操作可以把它的深度逐渐变成均摊O(logn),所以开始的树的形态不影响复杂度。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 struct spaly
 4 {
 5     int siz, fa, c[2], rev;
 6 }a[100005];
 7 int root, n;
 8  
 9 void push_up(int k)
10 {
11     a[k].siz = a[a[k].c[0]].siz + a[a[k].c[1]].siz + 1;
12 }
13  
14 void push_down(int k)
15 {
16     if(a[k].rev)
17     {
18         swap(a[k].c[0], a[k].c[1]), a[k].rev = 0;
19         a[a[k].c[0]].rev ^= 1, a[a[k].c[1]].rev ^= 1;
20     }
21 }
22  
23 void rotate(int &k, int x)
24 {
25     int y = a[x].fa, z = a[y].fa;
26     int dy = a[y].c[1] == x, dz = a[z].c[1] == y;
27     push_down(y);
28     if(k == y) k = x, a[x].fa = z;
29     else a[z].c[dz] = x, a[x].fa = z;
30     a[y].c[dy] = a[x].c[dy ^ 1], a[a[x].c[dy ^ 1]].fa = y;
31     a[x].c[dy ^ 1] = y, a[y].fa = x;
32     push_up(y);
33 }
34  
35 void splay(int &k, int x)
36 {
37     push_down(x);
38     while(k != x)
39     {
40         int y = a[x].fa, z = a[y].fa;
41         if(k != y)
42             if(a[y].c[1] == x ^ a[z].c[1] == y) rotate(k, x);
43             else rotate(k, y);
44         rotate(k, x);
45     }
46     push_up(x);
47 }
48  
49 int find(int k, int x)
50 {
51     if(!k) return 0;
52     push_down(k);
53     if(x <= a[a[k].c[0]].siz) return find(a[k].c[0], x);
54     if(x == a[a[k].c[0]].siz + 1) return k;
55     return find(a[k].c[1], x - a[a[k].c[0]].siz - 1);
56 }
57  
58 void printf(int k)
59 {
60     if(!k) return;
61     push_down(k), printf(a[k].c[0]);
62     if(k > 1 && k < n + 2) printf("%d ", k - 1);
63     printf(a[k].c[1]);
64 }
65  
66 int main()
67 {
68     int m, l, r;
69     scanf("%d%d", &n, &m);
70     for(int i = 1; i <= n + 2; i++)
71     {
72         a[i].siz = n + 3 - i;
73         a[i].fa = i - 1, a[i].c[1] = i + 1;
74     }
75     a[n + 2].c[1] = 0, root = 1;
76     while(m--)
77     {
78         scanf("%d%d", &l, &r);
79         splay(root, find(root, l));
80         splay(a[root].c[1], find(root, r + 2));
81         a[a[a[root].c[1]].c[0]].rev ^= 1;
82     }
83     printf(root);
84     puts("");
85     return 0;
86 }
View Code
原文地址:https://www.cnblogs.com/CtrlCV/p/5357702.html