【bzoj2329】[HNOI2011]括號修復 Splay
阿新 • • 發佈:2017-12-23
等於 調整 define clu 分享 microsoft printf jpg 復雜
題目描述
題解
Splay
由於有區間反轉操作,因此考慮Splay。
考慮答案:縮完括號序列後剩下的一定是 $a$ 個‘)‘+ $b$ 個‘(‘,容易發現答案等於 $\lceil\frac a2\rceil+\lceil\frac b2\rceil$ 。
怎麽維護:區間合並,對於每個節點維護子樹縮完括號序列後‘)‘和‘(‘的數目,然後pushup時考慮縮括號序列的過程,相應調整即可。
由於有Invent操作,因此還需要維護反括號序列縮完之後‘)‘和‘(‘的數目,並維護相應標記。
由於有Swap操作,因此需要維護相應標記。需要註意的是:這裏的Swap不是鏡面反轉,而是直接交換,換句話說就是翻轉後括號方向不變。因此不能直接交換‘)‘的數目和‘(‘的數目,而是相當於交換後再Invent一次,即交換‘)‘的數目和反括號序列‘(‘的數目、交換‘(‘的數目和反括號序列‘)‘的數目。
由於有Replace操作,因此還需要維護區間染色標記。
時間復雜度 $O(n\log n)$
#include <cstdio> #include <cstring> #include <algorithm> #define N 100010 using namespace std; int fa[N] , c[2][N] , si[N] , w[N] , sum[N][2][2] , tag[N] , rev[N] , flip[N] , root; char str[N]; inline void pushup(int x) { int l = c[0][x] , r = c[1][x]; si[x] = si[l] + si[r] + 1; sum[x][0][0] = sum[l][0][0] + max(sum[r][0][0] - sum[l][0][1] + w[x] , 0); sum[x][0][1] = sum[r][0][1] + max(sum[l][0][1] - sum[r][0][0] - w[x] , 0); sum[x][1][0] = sum[l][1][0] + max(sum[r][1][0] - sum[l][1][1] - w[x] , 0); sum[x][1][1] = sum[r][1][1] + max(sum[l][1][1] - sum[r][1][0] + w[x] , 0); } inline void pushdown(int x) { int l = c[0][x] , r = c[1][x]; if(rev[x]) { w[l] = -w[l] , tag[l] = -tag[l] , swap(sum[l][0][0] , sum[l][1][0]) , swap(sum[l][0][1] , sum[l][1][1]) , rev[l] ^= 1; w[r] = -w[r] , tag[r] = -tag[r] , swap(sum[r][0][0] , sum[r][1][0]) , swap(sum[r][0][1] , sum[r][1][1]) , rev[r] ^= 1; rev[x] = 0; } if(flip[x]) { swap(c[0][l] , c[1][l]) , swap(sum[l][0][0] , sum[l][1][1]) , swap(sum[l][0][1] , sum[l][1][0]) , flip[l] ^= 1; swap(c[0][r] , c[1][r]) , swap(sum[r][0][0] , sum[r][1][1]) , swap(sum[r][0][1] , sum[r][1][0]) , flip[r] ^= 1; flip[x] = 0; } if(tag[x]) { w[l] = w[r] = tag[l] = tag[r] = tag[x]; if(tag[x] == 1) { sum[l][0][0] = sum[l][1][1] = si[l] , sum[l][0][1] = sum[l][1][0] = 0; sum[r][0][0] = sum[r][1][1] = si[r] , sum[r][0][1] = sum[r][1][0] = 0; } else { sum[l][0][0] = sum[l][1][1] = 0 , sum[l][0][1] = sum[l][1][0] = si[l]; sum[r][0][0] = sum[r][1][1] = 0 , sum[r][0][1] = sum[r][1][0] = si[r]; } tag[x] = 0; } } int build(int l , int r) { if(l > r) return 0; int mid = (l + r) >> 1; c[0][mid] = build(l , mid - 1) , fa[c[0][mid]] = mid; c[1][mid] = build(mid + 1 , r) , fa[c[1][mid]] = mid; pushup(mid); return mid; } inline void rotate(int &k , int x) { int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1; if(y == k) k = x; else c[c[1][z] == y][z] = x; fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y; pushup(y) , pushup(x); } inline void splay(int &k , int x) { while(x != k) { int y = fa[x] , z = fa[y]; if(y != k) { if((c[0][y] == x) ^ (c[0][z] == y)) rotate(k , x); else rotate(k , y); } rotate(k , x); } } int find(int k , int x) { pushdown(k); if(x <= si[c[0][k]]) return find(c[0][k] , x); else if(x > si[c[0][k]] + 1) return find(c[1][k] , x - si[c[0][k]] - 1); else return k; } int split(int l , int r) { int a = find(root , l) , b = find(root , r + 2); splay(root , a) , splay(c[1][root] , b); return c[0][c[1][root]]; } int main() { int n , m , i , x , y , z; scanf("%d%d%s" , &n , &m , str + 2); for(i = 2 ; i <= n + 1 ; i ++ ) w[i] = (str[i] == ‘)‘ ? 1 : -1); root = build(1 , n + 2); while(m -- ) { scanf("%s%d%d" , str , &x , &y) , z = split(x , y); if(str[0] == ‘R‘) { scanf("%s" , str); if(str[0] == ‘)‘) sum[z][0][0] = sum[z][1][1] = si[z] , sum[z][0][1] = sum[z][1][0] = 0 , w[z] = tag[z] = 1; else sum[z][0][0] = sum[z][1][1] = 0 , sum[z][0][1] = sum[z][1][0] = si[z] , w[z] = tag[z] = -1; pushup(fa[z]) , pushup(root); } else if(str[0] == ‘S‘) swap(c[0][z] , c[1][z]) , swap(sum[z][0][0] , sum[z][1][1]) , swap(sum[z][0][1] , sum[z][1][0]) , flip[z] ^= 1 , pushup(fa[z]) , pushup(root); else if(str[0] == ‘I‘) w[z] = -w[z] , tag[z] = -tag[z] , swap(sum[z][0][0] , sum[z][1][0]) , swap(sum[z][0][1] , sum[z][1][1]) , rev[z] ^= 1 , pushup(fa[z]) , pushup(root); else printf("%d\n" , (sum[z][0][0] + 1) / 2 + (sum[z][0][1] + 1) / 2); } return 0; }
【bzoj2329】[HNOI2011]括號修復 Splay