【BZOJ1269】文本编辑器-Splay
维护一个字符串,支持插入,删除,翻转一段区间。
可以用Splay来做,光标位置可以用一个全局变量pos代替,移动光标操作就相应的修改pos就行了。
插入删除都是Splay基本操作,翻转区间需要打标记,下传的时候交换左右儿子就好了。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 5 using namespace std; 6 7 const int N = (1<<21) + 5; 8 9 int m, k; 10 char s[N], op[10]; 11 12 struct SplayTree{ 13 #define ls son[x][0] 14 #define rs son[x][1] 15 #define key_val son[son[rt][1]][0] 16 17 int sz, rt, son[N][2], pre[N]; 18 char val[N]; 19 inline void init(){ 20 pos = 1; 21 rt = sz = 0; 22 Newnode(rt,0,'$'); 23 Newnode(son[rt][1],rt,'$'); 24 size[rt] = 2; 25 } 26 inline void Newnode( int &x, int y, char w ){ 27 x = ++sz; 28 pre[x] = y; 29 val[x] = w; 30 size[x] = 1; 31 ls = rs = 0; 32 } 33 inline void Build( int &x, int y, int l, int r ){ 34 if ( l > r ) return; 35 int mid = (l+r)>>1; 36 Newnode( x,y,str[mid] ); 37 Build( ls,x,l,mid-1 ); 38 Build( rs,x,mid+1,r ); 39 pushup(x); 40 } 41 inline void pushup( int x ){ 42 size[x] = size[ls] + size[rs] + 1; 43 } 44 inline void pushdown( int x ){ 45 if ( !rev[x] ) return; 46 swap( ls,rs ); 47 rev[ls] ^= 1; 48 rev[rs] ^= 1; 49 rev[x] = 0; 50 } 51 inline void Link( int x, int y, int d ){ 52 pre[x] = y; son[y][d] = x; 53 } 54 inline void Rotate( int x, int d ){ 55 int y = pre[x], z = pre[y]; 56 pushdown(y);pushdown(x); 57 Link( son[x][d],y,!d ); 58 pre[x] = pre[y]; 59 if ( z ) Link( x,z,son[z][1]==y ); 60 Link( y,x,d ); 61 pushup(y); 62 } 63 inline void Splay( int x, int s ){ 64 pushdown(x); 65 while ( pre[x] != s ){ 66 int y = pre[x], z = pre[y]; 67 if ( z != s ){ 68 int d = (son[z][0]==y); 69 if ( son[y][d] == x ) Rotate(x,!d),Rotate(x,d); 70 else Rotate(y,d),Rotate(x,d); 71 }else Rotate(x,son[y][0]==x); 72 } 73 pushup(x); 74 if ( !s ) rt = x; 75 } 76 inline int find( int x, int k ){ 77 pushdown(x); 78 int tot = size[ls]+1; 79 if ( tot == k ) return x; 80 return tot>k ? find(ls,k) : find(rs,k-tot); 81 } 82 //----------------------------------- 83 inline void Prev(){pos--;} 84 inline void Next(){pos++;} 85 inline void Move( int k ){pos = k+1;} 86 inline void Get(){ 87 Splay(find(rt,pos+1),0); 88 putchar( val[rt] ); 89 puts( "" ); 90 } 91 inline void Rotate( int n ){ 92 int l = find(rt,pos); 93 int r = find(rt,pos+n+1); 94 Splay(l,0);Splay(r,l); 95 rev[key_val] ^= 1; 96 } 97 inline void Insert( int n ){ 98 for ( int i = 1; i <= n; i ++ ){ 99 str[i] = getchar(); 100 while ( str[i] < 32 || str[i] > 126 ) 101 str[i] = getchar(); 102 } 103 int l = find(rt,pos); 104 int r = find(rt,pos+1); 105 Splay(l,0);Splay(r,l); 106 Build(son[r][0],r,1,n); 107 pushup(r);pushup(l); 108 } 109 inline void Delete( int n ){ 110 int l = find(rt,pos); 111 int r = find(rt,pos+n+1); 112 Splay(l,0);Splay(r,l); 113 pre[key_val] = key_val = 0; 114 pushup(r);pushup(l); 115 } 116 //----------------------------Debug 117 inline void Travel( int x ){ 118 if ( !x ) return; 119 Travel(son[x][0]); 120 printf( "节点%2d :左儿子%2d 右儿子%2d ",x, son[x][0], son[x][1] ); 121 printf( "父节点%2d val = %2c size = %2d\n", pre[x], val[x], size[x] ); 122 Travel(son[x][1]); 123 } 124 void Debug(){ 125 puts( "--------------------" ); 126 printf( "%d\n", rt ); 127 Travel( rt ); 128 puts( "--------------------" ); 129 } 130 char str[N]; 131 int pos, size[N], rev[N]; 132 }sp; 133 int main(){ 134 sp.init(); 135 scanf( "%d", &m ); 136 for ( int i = 1; i <= m; i ++ ) 137 { 138 scanf( "%s", op ); 139 if ( op[0] == 'M' || op[0] == 'R' ) scanf( "%d", &k ); 140 if ( op[0] == 'I' || op[0] == 'D' ) scanf( "%d", &k ); 141 if ( op[0] == 'P' ) sp.Prev(); 142 if ( op[0] == 'N' ) sp.Next(); 143 if ( op[0] == 'G' ) sp.Get(); 144 if ( op[0] == 'M' ) sp.Move(k); 145 if ( op[0] == 'I' ) sp.Insert(k); 146 if ( op[0] == 'R' ) sp.Rotate(k); 147 if ( op[0] == 'D' ) sp.Delete(k); 148 } 149 return 0; 150 }