傳送門:>Here<
解法分析
用splay來維護這個序列。
一直沒有搞明白的是,這里的splay的節點究竟維護的是什么?是權值嗎?肯定不是,因為區間是會翻轉的,如果維護權值的話很快平衡樹就不再滿足性質。
然而從頭到尾,唯一始終統一的就是位置——始終是1~n. 因此考慮用節點來維護位置。
這樣在維護splay的時候,翻轉一段區間就相當於修改了這一段區間的位置,使原來小的現在大了,原來大的現在小了。放在樹上形象的看,就是原來作為父節點的左兒子的統統稱為了右兒子。反之亦然。因此只要找出連續的那一段區間,並且翻轉左右子樹即可。注意為了減少操作次數,可以打懶標記。
如何找出連續的那一段目標區間?由於要翻轉的是區間$[l, r]$,我們可以找到位置(注意,這里的位置也就是平衡樹維護的權值的排名了,因此位置i也就是排名第i的)l-1和r+1的點,分別旋轉到根節點和根節點的右子樹上。這樣,根節點的右子節點的左子樹就是這段區間了。(想一想,為什么)。特殊的,當邊界到達1或n時會溢出,因此我們加入哨兵節點-1和n+1。這樣位置i就是排名i+1了。
值得注意的是何時下傳懶標記——根據懶標記的優良傳統,不用就不翻轉。那唯一要用的時候就是詢問位置的時候了,因此只要find的時候下傳就可以了。另外翻轉兩次相當於不翻轉,所以用xor1會很方便。
/*By QiXingzhi*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int MAXN = 100010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ '-' && (c < '0' || c > '9')) c = getchar(); if(c == '-') w = -1, c = getchar(); while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar(); return x * w; } int n,m,L,R; struct Splay{ int ch[MAXN][2],size[MAXN],val[MAXN],fa[MAXN],tag[MAXN],num_node,root; inline bool Son(int f, int x){ return ch[f][1]==x; } inline void Update(int x){ size[x] = size[ch[x][1]] + size[ch[x][0]] + 1; } inline void Rotate(int x){ int f = fa[x], gf = fa[f]; bool p = Son(f, x), q = !p; ch[f][p] = ch[x][q]; fa[ch[x][q]] = f; ch[x][q] = f; fa[f] = x; fa[x] = gf; if(gf != 0){ ch[gf][Son(gf,f)] = x; }else{ root = x; } Update(x), Update(f); } inline void splay(int x, int target){ while(fa[x] != target){ int f = fa[x], gf = fa[f]; if(gf == target){ Rotate(x); return; } if(Son(gf,f) == Son(f,x)){ Rotate(f), Rotate(x); } else{ Rotate(x), Rotate(x); } } } inline void Insert(int v){ if(root == 0){ ++num_node; root = num_node; size[num_node] = 1; val[num_node] = v; return; } for(int x = root; x != 0; x = ch[x][v >= val[x]]){ bool b = v >= val[x]; if(ch[x][b] == 0){ ++num_node; ch[x][b] = num_node; size[num_node] = 1; val[num_node] = v; fa[ch[x][b]] = x; splay(ch[x][b], 0); } } } inline void Pushdown(int x){ if(x == 0) return; if(!tag[x]) return; int tmp = ch[x][0]; ch[x][0] = ch[x][1]; ch[x][1] = tmp; tag[x] = 0; tag[ch[x][0]] ^= 1; tag[ch[x][1]] ^= 1; } inline int Find(int _k){ int x = root; for(; x != 0;){ Pushdown(x); if(size[ch[x][0]] + 1 == _k){ return x; } if(size[ch[x][0]] >= _k){ x = ch[x][0]; } else{ _k -= size[ch[x][0]] + 1; x = ch[x][1]; } } } inline void Reverse(int L, int R){ if(L >= R) return; splay(Find(L), 0); splay(Find(R), root); tag[ch[ch[root][1]][0]] ^= 1; } inline void DEBUG(){ for(int i = 1; i <= n; ++i){ printf("%d-->%d lson:%d rson:%d\n",i,val[i],ch[i][0],ch[i][1]); } } }qxz; int main(){ // freopen(".in","r",stdin); n=r, m=r; qxz.Insert(-1); qxz.Insert(n+1); for(int i = 1; i <= n; ++i){ qxz.Insert(i); } // qxz.DEBUG(); for(int i = 1; i <= m; ++i){ L=r, R=r; qxz.Reverse(L,R+2); } for(int i = 1; i <= n; ++i){ printf("%d ", qxz.val[qxz.Find(i+1)]); } return 0; }