HDU4453--Looploop (Splay伸展树)

Looploop

XXX gets a new toy named Looploop. The toy has N elements arranged in a loop, an arrow pointing to one of the elements, and two preset parameters k1 and k2. Every element has a number on it.

The figure above shows a Looploop of 6 elments. Let‘s assuming the preset parameter k1 is 3, and k2 is 4.
XXX can do six operations with the toy.

1: add x 
Starting from the arrow pointed element, add x to the number on the clockwise first k2 elements.

2: reverse
Starting from the arrow pointed element, reverse the first k1 clockwise elements.

3: insert x 
Insert a new element with number x to the right (along clockwise) of the arrow pointed element.

4: delete 
Delete the element the arrow pointed and then move the arrow to the right element.

5: move x 
x can only be 1 or 2. If x = 1 , move the arrow to the left(along the counterclockwise) element, if x = 2 move the arrow to the right element.

6: query
Output the number on the arrow pointed element in one line.

XXX wants to give answers to every query in a serial of operations.

Input

There are multiple test cases.
For each test case the first line contains N,M,k1,k2(2≤k1<k2≤N≤105, M≤105) indicating the initial number of elements, the total number of operations XXX will do and the two preset parameters of the toy. 
Second line contains N integers ai(-104≤ai≤104) representing the N numbers on the elements in Looploop along clockwise direction. The arrow points to first element in input at the beginning. 
Then m lines follow, each line contains one of the six operations described above.
It is guaranteed that the "x" in the "add","insert" and "move" operations is always integer and its absolute value ≤104. The number of elements will never be less than N during the operations. 
The input ends with a line of 0 0 0 0.

Output

For each test case, output case number in the first line(formatted as the sample output). Then for each query in the case, output the number on the arrow pointed element in a single line.

Sample Input

5 1 2 4
3 4 5 6 7
query
5 13 2 4
1 2 3 4 5
move 2
query
insert 8
reverse
query
add 2
query
move 1
query
move 1
query
delete
query
0 0 0 0

Sample Output

Case #1:

3

Case #2:

2

8

10

1

5

1

2012 Asia Hangzhou Regional Contest

题意很简单,就像题目中 图片中描述的一样。Splay大法好啊。

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <algorithm>
  5 using namespace std;
  6 const int inf = 0x3f3f3f3f;
  7 const int maxn = 100086;
  8 int pre[maxn],ch[maxn][2],key[maxn],addv[maxn],rev[maxn],siz[maxn];
  9 int tot1,tot2,root,s[maxn];  //s为内存池
 10 int a[maxn],n,m,k1,k2;
 11 void update_add(int r,int val)
 12 {
 13     if (!r)
 14         return;
 15     key[r] += val;
 16     addv[r] += val;
 17 }
 18 void update_rev(int r)
 19 {
 20     if (!r)
 21         return;
 22     swap(ch[r][0],ch[r][1]);
 23     rev[r] ^= 1;
 24 }
 25 void push_down(int r)
 26 {
 27     if (rev[r])
 28     {
 29         update_rev(ch[r][0]);
 30         update_rev(ch[r][1]);
 31         rev[r] = 0;
 32     }
 33     if (addv[r])
 34     {
 35         update_add(ch[r][0],addv[r]);
 36         update_add(ch[r][1],addv[r]);
 37         addv[r] = 0;
 38     }
 39 }
 40 void push_up(int r)
 41 {
 42     siz[r] = siz[ch[r][0]] + siz[ch[r][1]] + 1;
 43 }
 44 void NewNode (int &r,int father,int k)
 45 {
 46     if (tot2)
 47         r = s[tot2--];
 48     else
 49         r = ++tot1;
 50     pre[r] = father;
 51     siz[r] = 1;
 52     rev[r] = 0;
 53     addv[r] = 0;
 54     ch[r][0] = ch[r][1] = 0;
 55     key[r] = k;
 56 }
 57 void build(int &x,int l,int r,int father)
 58 {
 59     if (l > r)
 60         return ;
 61     int mid = (l + r) >> 1;
 62     NewNode(x,father,a[mid]);
 63     build(ch[x][0],l,mid-1,x);
 64     build(ch[x][1],mid+1,r,x);
 65     push_up(x);
 66 }
 67 void init()
 68 {
 69     tot1 = tot2 = root = 0;
 70     for (int i = 1; i <= n; i++)
 71         scanf ("%d",a+i);
 72     NewNode(root,0,inf);
 73     NewNode(ch[root][1],root,inf);
 74     build(ch[ch[root][1]][0],1,n,ch[root][1]);
 75     push_up(root);
 76     push_up(ch[root][1]);
 77 }
 78 void Rotate(int r,int kind)
 79 {
 80     int y = pre[r];
 81     push_down(y);
 82     push_down(r);
 83     ch[y][!kind] = ch[r][kind];
 84     pre[ch[r][kind]] = y;
 85     if (pre[y])
 86         ch[pre[y]][ch[pre[y]][1] == y] = r;
 87     ch[r][kind] = y;
 88     pre[r] = pre[y];
 89     pre[y] = r;
 90     push_up(y);
 91 }
 92
 93 void Splay(int r,int goal)
 94 {
 95     push_down(r);
 96     while (pre[r] != goal)
 97     {
 98         if (pre[pre[r]] == goal)
 99         {
100             push_down(pre[r]);
101             push_down(r);
102             Rotate(r,ch[pre[r]][0] == r);
103         }
104         else
105         {
106             int y = pre[r];
107             int kind = (ch[pre[y]][1] == y);
108             push_down(pre[y]);
109             push_down(y);
110             push_down(r);
111             if (ch[y][kind] == r)
112             {
113                 Rotate(y,!kind);
114                 Rotate(r,!kind);
115             }
116             else
117             {
118                 Rotate(r,kind);
119                 Rotate(r,!kind);
120             }
121         }
122     }
123     push_up(r);
124     if (goal == 0)
125         root = r;
126 }
127 int Get_kth(int r,int k)
128 {
129     push_down(r);
130     int t = siz[ch[r][0]] + 1;
131     if (t == k)
132         return r;
133     if (t > k)
134         return Get_kth(ch[r][0],k);
135     else
136         return Get_kth(ch[r][1],k-t);
137 }
138 void ADD(int x)
139 {
140     Splay (Get_kth(root,1),0);
141     Splay(Get_kth(root,k2+2),root);
142     update_add(ch[ch[root][1]][0],x);
143     push_up(ch[root][1]);
144     push_up(root);
145 }
146 void Reverse(int u,int v)
147 {
148     Splay(Get_kth(root,u),0);
149     Splay(Get_kth(root,v+2),root);
150     update_rev(ch[ch[root][1]][0]);
151     push_up(ch[root][1]);
152     push_up(root);
153 }
154 void Insert(int x)
155 {
156     Splay(Get_kth(root,2),0);
157     Splay(Get_kth(root,3),root);
158     NewNode(ch[ch[root][1]][0],ch[root][1],x);
159     push_up(ch[root][1]);
160     push_up(root);
161 }
162 void eraser(int r)
163 {
164     if (!r)
165         return;
166     s[++tot2] = r;
167     eraser(ch[r][0]);
168     eraser(ch[r][1]);
169 }
170 void Delete()
171 {
172     Splay(Get_kth(root,1),0);
173     Splay(Get_kth(root,3),root);
174     eraser(ch[ch[root][1]][0]);
175     pre[ch[ch[root][1]][0]] = 0;
176     ch[ch[root][1]][0] = 0;
177     push_up(ch[root][1]);
178     push_up(root);
179 }
180 void Move(int x)               //Move操作就是两个 区间reverse操作。
181 {
182     if (x == 1)
183     {
184         Reverse(1,n);
185         Reverse(2,n);
186     }
187     if (x == 2)
188     {
189         Reverse(1,n);
190         Reverse(1,n-1);
191     }
192 }
193 int query()
194 {
195     Splay(Get_kth(root,1),0);
196     Splay(Get_kth(root,3),root);
197     return key[ch[ch[root][1]][0]];
198 }
199 int main(void)
200 {
201     #ifndef ONLINE_JUDGE
202         freopen("in.txt","r",stdin);
203     #endif
204     int cas = 1;
205     while (~scanf ("%d%d%d%d",&n,&m,&k1,&k2))
206     {
207         if (n == 0 && m == 0 && k1 == 0 && k2 == 0)
208             break;
209         printf("Case #%d:\n",cas++);
210         init();
211         for (int i = 0; i < m; i++)
212         {
213             char op[8];
214             int x;
215             scanf ("%s",op);
216             if (op[0] == ‘a‘)
217             {
218                 scanf ("%d",&x);
219                 ADD(x);
220             }
221             if (op[0] == ‘r‘)
222                 Reverse(1,k1);
223             if (op[0] == ‘i‘)
224             {
225                 scanf ("%d",&x);
226                 Insert(x);
227                 n++;           // insert一个数  n自然加1
228             }
229             if (op[0] == ‘d‘)
230             {
231                 Delete();
232                 n--;          //delete一个数 n减1
233             }
234             if (op[0] == ‘m‘)
235             {
236                 scanf ("%d",&x);
237                 Move(x);
238             }
239             if (op[0] == ‘q‘)
240                 printf("%d\n",query());
241         }
242     }
243     return 0;
244 }
时间: 2024-11-12 05:52:47

HDU4453--Looploop (Splay伸展树)的相关文章

Splay伸展树学习笔记

Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Tarjan 优点:每次查询会调整树的结构,使被查询频率高的条目更靠近树根. Tree Rotation 树的旋转是splay的基础,对于二叉查找树来说,树的旋转不破坏查找树的结构. Splaying Splaying是Splay Tree中的基本操作,为了让被查询的条目更接近树根,Splay Tree

bzoj1208 splay伸展树

splay伸展树主要有两种操作形式 (1)正常的二叉树插入形式 功能:a.查找 b.求最大值 c.最小值 d.求前驱 e.求后继 f.删点 g.合并splay树 (这里的删除直接利用splay树的结点下标) (2)区间形式 (插入是以区间形式插入的) 区间形式的伸展树相当于线段树,支持线段树的所有操作,并且还支持区间插入这个功能, 比如操作区间[a,b],将根设为a-1,根的右孩子设为b+1,那么根的右孩子的左孩子就是所求区间 某个点插入区间也是一个道理 需要注意的是,这里init()自动生成了

【学时总结】◆学时&#183;VI◆ SPLAY伸展树

◆学时·VI◆ SPLAY伸展树 平衡树之多,学之不尽也-- ◇算法概述 二叉排序树的一种,自动平衡,由 Tarjan 提出并实现.得名于特有的 Splay 操作. Splay操作:将节点u通过单旋.双旋移动到某一个指定位置. 主要目的是将访问频率高的节点在不改变原顺序的前提下移动到尽量靠近根节点的位置,以此来解决同一个(相似)问题的多次查询. 但是在非降序查询每一个节点后,Splay 树会变为一条链,降低运算效率. ◇原理&细解 (1)旋转操作 二叉排序树必须满足 左儿子<根节点<右

Splay伸展树

伸展树,感觉对我这种菜鸟还是有些吃力,主要也是旋转的时候吧,把要查询的节点旋转到根节点,看网上是有两种方法,一是从上到下,一是从下到上.从上到下,是把树拆分成中树,左树和右树,始终保证目标节点在中树,不断向下把中树的节点添到右树或者左树,直到目标节点为中树的根,再将三树合并起来.另外一种从下到上,旋转操作类似AVL树中的旋转,但是判断好像不是很好写,我写的是从上到下的,另外删除也很巧妙,先把目标节点旋转到根,若此时左子树为空直接删除,否则找到左子树最右的节点当头,利用伸展树的特殊旋转就可以一步删

UVA 11922 Permutation Transformer —— splay伸展树

题意:根据m条指令改变排列1 2 3 4 - n ,每条指令(a, b)表示取出第a~b个元素,反转后添加到排列尾部 分析:用一个可分裂合并的序列来表示整个序列,截取一段可以用两次分裂一次合并实现,粘贴到末尾可以用一次合并实现. 翻转可以采用在每个结点上做标记的方法,flip = 1意味着将这棵子树翻转,可以类似线段树用一个pushdown()实现标记向下传递. 可以发现当前排列就是伸展树的中序遍历序列.中序遍历打印结果即可. 注意代码中设置了虚拟首结点0的技巧. 代码如下: 1 #includ

Splay伸展树入门(单点操作,区间维护)

ps:终于学会了伸展树的区间操作,做一个完整的总结,总结一下自己的伸展树的单点操作和区间维护,顺便给未来的总结复习用. splay是一种平衡树,[平均]操作复杂度O(nlogn).首先平衡树先是一颗二叉搜索树,刚刚开始学的时候找题hash数字的题先测板子... 后来那题被学长改了数据不能用平衡树测了...一道二分数字的题. 二叉搜索树的功能是,插入一个数字,在O(logn)的时间内找到它,并操作,插入删除等.但是可能会让二叉搜索树退化成链,复杂度达到O(n) 原文地址:https://www.c

codeforces 38G - Queue splay伸展树

题目 https://codeforces.com/problemset/problem/38/G 题意: 一些人按顺序进入队列,每个人有两个属性,地位$A$和能力$C$ 每个人进入时都在队尾,并最多可以和前一位互换$C$次,如果前一位的地位高于自己,则无法继续互换. 最终一次性输出整个队列 题解: splay维护动态的队列 可以用类似权值线段树的思维去考虑 对于每个点,保存其子节点的最大值,自身的值,与子树的大小 对于每次插入时,若能跨过整颗右子树与当前节点,则向左走,否则向右 可以保证整个子

splay伸展树模板

1 struct SplayTree 2 { 3 4 const static int maxn = 1e5 + 15; 5 6 int tot,root,ch[maxn][2], key[maxn], sz[maxn], lz[maxn], fa[maxn]; 7 8 void init( int x, int v = 0, int par = 0 ) 9 { 10 ch[x][0]=ch[x][1]=0, fa[x]= par, key[x] = v, sz[x] = 1; 11 } 12

树-伸展树(Splay Tree)

伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二叉查找树,即它具有和二叉查找树一样的性质:假设x为树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x].如果y是x的左子树中的一个结点,则key[y] <= key[x]:如果y是x的右子树的一个结点,则key[y] >= key[x]. (02) 除了拥有二叉查找树的性质