题目不说了,就是区间翻转

 

传送门: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 }