大概了解了一下splay的各种操作, 至今没找到可信度高的复杂度证明 , 默认是log级别吧...
第一次写很多细节会写错
郁闷的出纳员:成段更新、删除、懒惰标记
top2,que[maxn],recover[maxn]都是回收内存用到的.
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 #include <ctime> 7 using namespace std; 8 const int maxn = 100100; 9 const int inf = 1000000000; 10 int root , sz[maxn] , son[maxn][2] , pre[maxn] , cnt , 11 top1 , top2 , recover[maxn] , que[maxn] , val[maxn] , lz[maxn]; 12 13 struct SplayTree 14 { 15 void pushdown(int x) 16 { 17 if (lz[x]) 18 { 19 if (son[x][0]) lz[ son[x][0] ] += lz[x] , val[ son[x][0] ] += lz[x]; 20 if (son[x][1]) lz[ son[x][1] ] += lz[x] , val[ son[x][1] ] += lz[x]; 21 lz[x] = 0; 22 } 23 } 24 void pushup(int x) 25 { 26 if (x) sz[x] = sz[ son[x][0] ] + sz[ son[x][1] ] + 1; 27 } 28 inline void Rotate(int x,int f) 29 { 30 int y = pre[x]; 31 pushdown(y); 32 pushdown(x); 33 son[y][!f] = son[x][f]; 34 pre[ son[x][f] ] = y; 35 pre[x] = pre[y]; 36 if (pre[x]) son[ pre[y] ][ son[pre[y]][1] == y ] =x; 37 son[x][f] = y; 38 pre[y] = x; 39 pushup(y); 40 } 41 inline void splay(int x,int goal) 42 { 43 pushdown(x); 44 while (pre[x] != goal) 45 { 46 if (pre[pre[x]] == goal) Rotate(x , son[pre[x]][0] == x); 47 else 48 { 49 int y = pre[x] , z = pre[y] , f = (son[z][0]==y); 50 if (son[y][f] == x) Rotate(x , !f) , Rotate(x , f); 51 else Rotate(y , f) , Rotate(x , f); 52 } 53 } 54 pushup(x); 55 if (goal == 0) root = x; 56 } 57 58 inline void RotateTo(int k , int goal) 59 { 60 int x = root; 61 pushdown(x); 62 if (k==0) return; 63 while (sz[ son[x][0] ]+1 != k) 64 { 65 if (k <= sz[ son[x][0] ]) x = son[x][0]; 66 else 67 { 68 k -= (sz[ son[x][0] ]+1); 69 x = son[x][1]; 70 } 71 pushdown(x); 72 } 73 splay(x , goal); 74 } 75 76 inline void erase(int x) 77 { 78 if (!x) return; 79 int father = pre[x]; 80 int head = 0 , tail = 0; 81 for (que[tail++] = x ; head < tail ; head++ ) 82 { 83 recover[top2++] = que[head]; 84 // lz[ que[head] ] = sz[ que[head] ] = 0; 这句可注释? 85 if (son[ que[head] ][0]) que[tail++] = son[ que[head] ][0]; 86 if (son[ que[head] ][1]) que[tail++] = son[ que[head] ][1]; 87 } 88 son[ father ][ son[father][1] == x ] = 0; 89 pushup(father); 90 } 91 void init() 92 { 93 root = top1 = top2 = 0; 94 son[0][0] = son[0][1] = 0; 95 sz[0] = 0; 96 cnt = 0; 97 } 98 void Newnode(int &x , int num) 99 { 100 if (top2) x = recover[--top2]; 101 else x = ++top1; 102 pre[x] = lz[x] = son[x][0] = son[x][1] = 0; 103 sz[x] = 1; val[x] = num; 104 } 105 void ins(int num) 106 { 107 int x; 108 if (root == 0) { Newnode(root,num); return; } 109 for ( x=root ; ; ) 110 { 111 pushdown(x); 112 if ( son[x][ val[x] < num ]) x = son[x][ val[x] < num ]; 113 else 114 { 115 Newnode( son[x][ val[x] < num ] , num); 116 pre[ son[x][ val[x] < num ] ] = x; 117 splay(son[x][ val[x] < num ] , 0); 118 return; 119 } 120 } 121 } 122 void maintain(int m) 123 { 124 int k=0 , cur=root; 125 while (cur) 126 { 127 pushdown(cur); 128 if (val[cur] >= m) cur = son[cur][0]; 129 else 130 { 131 k += sz[ son[cur][0] ]+1; 132 cur = son[cur][1]; 133 } 134 } 135 if (k == sz[root]) 136 { 137 cnt += sz[root]; 138 erase(root); 139 root = 0; 140 return; 141 } 142 RotateTo(k+1,0); 143 RotateTo(k,root); 144 cnt += sz[ son[root][0] ]; 145 erase(son[root][0]); 146 pushup(root); 147 } 148 void Add(int num,int m) 149 { 150 if (!root) return; 151 val[root] += num; 152 lz[root] += num; 153 maintain(m); 154 } 155 int find(int k) 156 { 157 int cur = root; 158 if (sz[root] < k) return -1; 159 k = sz[root]-k+1; 160 while (sz[ son[cur][0] ]+1 != k) 161 { 162 pushdown(cur); 163 if (sz[ son[cur][0] ] >= k) cur = son[cur][0]; 164 else 165 { 166 k -= sz[ son[cur][0] ] + 1; 167 cur = son[cur][1]; 168 } 169 } 170 return val[cur]; 171 } 172 };SplayTree spt; 173 int n,m,t; 174 char s[100]; 175 int main() 176 { 177 freopen("test","r",stdin); 178 while (scanf("%d%d",&n,&m) != EOF) 179 { 180 spt.init(); 181 while (n--) 182 { 183 scanf("%s%d",s,&t); 184 // printf("%s %d\n",s,t); 185 if (s[0] == 'I') 186 { 187 if (t<m) continue; 188 spt.ins(t); 189 } 190 else if (s[0] == 'A') spt.Add(t,m); 191 else if (s[0] == 'S') 192 spt.Add(-t,m); 193 else if (s[0] == 'F') 194 printf("%d\n",spt.find(t)); 195 } 196 printf("%d\n",cnt); 197 } 198 return 0; 199 }
log:
(1) find 和 RotateTo 的传参 k , 特殊的k值会造成deadloop 需要特判.(tle)
(2) erase 的传参x 不能为0 否则sz[0] 会被pushup成非0值 造成运行错误.(re)
(3) 统计cnt值 的先后顺序 : 先 += 再 erase.(wa)
(4) 删除结点后忘记pushup(wa)
(5) 删除结点的子树的根为root时要特判(wa)
(6) Newnode要给pre[x] 赋值为0(tle)
Training Camp, Andrew Stankevich Contest 27 (PZ Summer 2007: ASC 27) H: move to front
题意是对初始排列为1,2...n的队列进行m次操作,每次把第l至第r的人提前至队首,输出最后的队列.
用跳表写O(n*sqrt(n))的超时,splay在此题的效率更高.
1 #define maxn 100010 2 int n,m; 3 int rt,sz[maxn],son[maxn][2],pre[maxn], 4 top1,val[maxn],lz[maxn]; 5 vector<int> arr; 6 struct SplayTree 7 { 8 void pushup(int x) 9 { 10 if (x) sz[x] = sz[ son[x][0] ] + sz[ son[x][1] ] + 1; 11 } 12 inline void Rotate(int x,int f) 13 { 14 int y = pre[x]; 15 son[y][!f] = son[x][f]; 16 pre[ son[x][f] ] = y; 17 pre[x] = pre[y]; 18 if (pre[x]) son[ pre[y] ][ son[pre[y]][1]==y ] = x; 19 son[x][f] = y; 20 pre[y] = x; 21 pushup(y); 22 } 23 inline void splay(int x,int goal) 24 { 25 if (x==goal) return; 26 while (pre[x] != goal) 27 { 28 if (pre[pre[x]] == goal) Rotate(x,son[pre[x]][0]==x); 29 else 30 { 31 int y = pre[x] , z = pre[y] , f = (son[z][0]==y); 32 if (son[y][f]==x) Rotate(x,!f) , Rotate(x,f); 33 else Rotate(y,f) , Rotate(x,f); 34 } 35 } 36 pushup(x); 37 if (goal==0) rt=x; 38 } 39 inline void RotateTo(int k,int goal) 40 { 41 int x = rt; 42 while (sz[ son[x][0] ]+1 != k) 43 { 44 if (k <= sz[ son[x][0] ]) x = son[x][0]; 45 else 46 { 47 k -= (sz[ son[x][0] ]+1); 48 x = son[x][1]; 49 } 50 } 51 splay(x,goal); 52 } 53 void init() 54 { 55 rt = son[0][0] = son[0][1] = sz[0] = 0; 56 } 57 void Newnode(int &x , int num) 58 { 59 x = ++ top1; 60 pre[x] = lz[x] = son[x][0] = son[x][1] = 0; 61 val[x] = num; 62 sz[x] = 1; 63 } 64 void MakeTree(int& x,int l,int r,int fa) 65 { 66 if (l>r) return; 67 Newnode(x,mid); 68 pre[x] = fa;; 69 MakeTree(son[x][0],l,mid-1,x); 70 MakeTree(son[x][1],mid+1,r,x); 71 pushup(x); 72 } 73 void div(int l,int r) 74 { 75 l++; r++; //将区间下标转化成序数 76 RotateTo(l-1,0); 77 RotateTo(r+1,rt); 78 int x = son[rt][1]; 79 int y = son[x][0]; 80 pre[y] = 0; 81 son[x][0]=0; 82 pushup(x); 83 pushup(rt); 84 85 RotateTo(2,0); 86 int idx0 = son[rt][0]; 87 son[rt][0] = 0; 88 pre[idx0] = 0; 89 pushup(rt); 90 91 son[rt][0] = y; 92 pre[y] = rt; 93 pushup(rt); 94 95 RotateTo(1,0); 96 son[rt][0] = idx0; 97 pre[idx0] = rt; 98 pushup(rt); 99 } 100 void GetArr(int x) 101 { 102 if (son[x][0])GetArr(son[x][0]); 103 if (1<=val[x]&&val[x]<=n) 104 arr.push_back(val[x]); 105 if (son[x][1])GetArr(son[x][1]); 106 } 107 void Travel(int x) 108 { 109 printf("id: %2d , val: %2d , sz: %2d , ls: %2d , lsz: %2d , rs: %2d , rsz: %2d\n",x,val[x],sz[x],son[x][0], 110 sz[son[x][0]],son[x][1],sz[son[x][1]]); 111 if (son[x][0]) Travel(son[x][0]); 112 if (son[x][1]) Travel(son[x][1]); 113 } 114 void debug(int x) 115 { 116 Travel(x); 117 } 118 119 };SplayTree spt; 120 void Print() 121 { 122 arr.clear(); 123 spt.GetArr(rt); 124 for (unsigned int i=0 ; i<arr.size() ; i++ ) 125 { 126 if (i) printf(" "); 127 printf("%d",arr[i]); 128 }printf("\n\n"); 129 } 130 int main() 131 { 132 scanf("%d%d",&n,&m); 133 spt.init(); 134 spt.MakeTree(rt,0,n+1,0); 135 int l,r; 136 while (m--) 137 { 138 scanf("%d%d",&l,&r); 139 spt.div(l,r); 140 } 141 Print(); 142 return 0; 143 }
log:
(1) 跳表超时;(tle)
(2) 没有多插入0,n+1来表示首尾元素,导致[1,x]和[x,n]这种区间提取不出来;(tle,wa...)
(3) 通过 “提取区间后将该区间拆下,再合并到根的右边” 来实现将[l,r]提到队首的操作,
但是在合并之前应该先将0元素拆下再合并,最后合并0元素,这样才能保证0元素始终在队首,否则接下来操作中[l,r]中可能包含了0.