【高级数据结构】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.

转载于:https://www.cnblogs.com/eggeek/archive/2013/01/08/2851288.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值