【高级数据结构】splay

  大概了解了一下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 }
View Code

log:

(1) 跳表超时;(tle)

(2) 没有多插入0,n+1来表示首尾元素,导致[1,x]和[x,n]这种区间提取不出来;(tle,wa...)

(3) 通过 “提取区间后将该区间拆下,再合并到根的右边” 来实现将[l,r]提到队首的操作,

但是在合并之前应该先将0元素拆下再合并,最后合并0元素,这样才能保证0元素始终在队首,否则接下来操作中[l,r]中可能包含了0.

你可能感兴趣的:(数据结构)