题目不说了,就是区间翻转
传送门:BZOJ 3223 和 CodeVS 3243
第一道题中是1~n的区间翻转,而第二道题对于每个1~n还有一个附加值
实际上两道题的思路是一样的,第二题把值对应到位置就行了
这里我们用伸展树来解决,但其中用到了线段树中的标记思想
对于一个长度的为n的序列,我们把它的每一位向后移动一位,即1~n → 2~n+1,然后再在序列前后分别补上一位:1和n+2。所以我们需要建立一颗节点数为n+2的伸展树,而原序列中的1~n位分别对应新序列中的2~n+1位。
对于每次询问的l和r,实际上就是l+1和r+1,首先找到l+1前一位对应的元素和r+1后一位对应的元素,即l和r+2分别对应的元素的序号。然后将l对应元素通过splay操作旋转到根节点,将r+2对应元素旋转到根节点的右儿子,由排序二叉树的性质可知,r+2的左儿子就是序列l+1~r+1,也就是询问中需要翻转的区间。对r+2的左儿子直接打上标记,在之后找元素序号的时候要记得把标记下传,同时用swap操作来达到翻转的目的。
splay操作和rotate操作在此不赘述。
最后输出的时候,同样查找2~n+1对应的元素序号,将得到的值减1还原,对于CodeVS 3243就再套一个值输出即可。
这里给出BZOJ 3223的代码。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #include <algorithm> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 #include <queue> 9 #include <string> 10 #include <map> 11 typedef long long ll; 12 using namespace std; 13 const int MAXN = 100020; 14 int n, m; 15 int root; 16 int son[MAXN][2], fa[MAXN], lazy[MAXN], siz[MAXN]; 17 18 inline int gi() { 19 char c; 20 int sum = 0, f = 1; 21 c = getchar(); 22 while (c < '0' || c > '9') { 23 if (c == '-') 24 f = -1; 25 c = getchar(); 26 } 27 while (c >= '0' && c <= '9') { 28 sum = sum * 10 + c - '0'; 29 c = getchar(); 30 } 31 return sum * f; 32 } 33 34 void build(int l, int r, int f) { 35 if (l > r) 36 return; 37 if (l == r) { 38 siz[l] = 1; 39 fa[l] = f; 40 son[f][l > f] = l; 41 return; 42 } 43 int mid = (l + r) >> 1; 44 build(l, mid - 1, mid); 45 build(mid + 1, r, mid); 46 siz[mid] = siz[son[mid][0]] + siz[son[mid][1]] + 1; 47 fa[mid] = f; 48 son[f][mid > f] = mid; 49 } 50 51 void pushdown(int o) { 52 swap(son[o][0], son[o][1]); 53 lazy[son[o][0]] ^= 1; 54 lazy[son[o][1]] ^= 1; 55 lazy[o] = 0; 56 } 57 58 int find(int o, int p) { 59 if (lazy[o]) 60 pushdown(o); 61 int l = son[o][0]; 62 int r = son[o][1]; 63 if (siz[l] + 1 == p) 64 return o; 65 if (siz[l] >= p) 66 return find(l, p); 67 else 68 return find(r, p - siz[l] - 1); 69 } 70 71 void rotate(int x, int &to) { 72 int l, r; 73 int f = fa[x]; 74 int ff = fa[f]; 75 l = son[f][0] == x ? 0 : 1; 76 r = l ^ 1; 77 if (f == to) 78 to = x; 79 else 80 son[ff][son[ff][1] == f] = x; 81 fa[x] = fa[f]; 82 fa[f] = x; 83 fa[son[x][r]] = f; 84 son[f][l] = son[x][r]; 85 son[x][r] = f; 86 siz[f] = siz[son[f][0]] + siz[son[f][1]] + 1; 87 siz[x] = siz[son[x][0]] + siz[son[x][1]] + 1; 88 } 89 90 void splay(int x, int &to) { 91 while (x != to) { 92 int f = fa[x]; 93 int ff = fa[f]; 94 if (f != to) { 95 if ((son[f][0] == x) ^ (son[ff][0] == f)) 96 rotate(x, to); 97 else 98 rotate(f, to); 99 } 100 rotate(x, to); 101 } 102 } 103 104 void reserve(int l, int r) { 105 int x = find(root, l); 106 int y = find(root, r + 2); 107 splay(x, root); 108 splay(y, son[x][1]); 109 lazy[son[y][0]] ^= 1; 110 } 111 112 int main() { 113 n = gi(); 114 m = gi(); 115 build(1, n + 2, 0); 116 root = (n + 3) >> 1; 117 for (int i = 1; i <= m; i++) { 118 int l = gi(); 119 int r = gi(); 120 reserve(l, r); 121 } 122 for (int i = 2; i <= n + 1; i++) 123 printf("%d ", find(root, i) - 1); 124 return 0; 125 }