• splay树:hdu4453 Looploop


    题目链接如下:

    Problem - 4453

    主要是要对区间操作和这种splay树的性质比较清楚。

    关于区间我们设立两个额外节点,用来设立最开始的左右区间。

    性质方面,其实就是二叉搜索树的性质,这里的体现就是中序遍历就是顺时针访问输入数据,逆中序就是逆时针。

    以下是思路:

    我们对每一组输入,首先创建两个节点,用来表示最左最右区间,这样对于后边限定范围十分有帮助。

    有几个比较有意思的操作:

    1.建树

    在这里的建树就是建立一颗二叉搜索树,这个搜索的key是针对输入顺序来说的,而每个树节点又需要表示一些额外的信息比如前驱,孩子节点,以及存储的输入等等。这里还得存储翻转和加标记,一遍后续旋转过程中动态更新。

    所以我们最初建立的树是长这样的:

    其实这应该是区间操作的核心,就是这个二叉搜索树是左端点和右端点之间的。

    2.add

    要给顺时针的k2个数加上一个数x,那么我们也就是要从当前指针指向的节点tp往后中序遍历一共k2个几点,把这k2个节点进行加一个数的操作。我们首先把左区间旋转到根的位置,然后把当前指针指向节点旋转到根下面,而这个节点的左边的子树,也就是按照顺时针访问的最后几个元素(逆时针开始的几个),把他给砍掉,再把最右节点的前一个节点转到根,接着把刚刚砍掉的左子树放到最后一个节点的左子树上,也就是当前根节点的右孩子的左孩子上面,这样,在中序遍历的时候,就已经变成了以指针指向的节点为起点,顺时针直到访问到最后一个节点。

    这个时候我们还要给当前指针指向的节点到第k2个数都加上一个数x对吧,那么还是老办法,把左区间端点转到根,把第k2+2个数转到root下面,那么此时root的左子树就是[2,k2+1]次序的数,我们把这个树的根打上加的标记,在后续过程动态更新,那么就完成了我们的操作。

    而add操作明白了之后,后续的区间操作也就大同小异。

    代码如下所示:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. using namespace std;
    13. #define keyv tree[tree[root][1]][0]
    14. #define lt(r) tree[r][0]
    15. #define rt(r) tree[r][1]
    16. const int MAXN=2e5+1;
    17. int pre[MAXN],sz[MAXN],rev[MAXN],add[MAXN],tree[MAXN][2],key[MAXN];
    18. int root,tot1,tot2;
    19. int s[MAXN],a[MAXN];
    20. int n,q,k1,k2;
    21. int tp;
    22. void newnode(int &r,int fa,int k){
    23. if (tot2) r=s[tot2--];
    24. else r=++tot1;
    25. key[r]=k;
    26. pre[r]=fa;
    27. add[r]=rev[r]=lt(r)=rt(r)=0;
    28. sz[r]=1;
    29. }
    30. void update_rev(int r){
    31. if (!r) return;
    32. swap(lt(r), rt(r));
    33. rev[r]^=1;
    34. }
    35. void update_add(int r,int v){
    36. if (!r) return;
    37. key[r]+=v;
    38. add[r]+=v;
    39. }
    40. void pushup(int r){
    41. sz[r]=sz[lt(r)]+sz[rt(r)]+1;
    42. }
    43. void pushdown(int r){
    44. if (rev[r]){
    45. update_rev(lt(r));
    46. update_rev(rt(r));
    47. rev[r]=0;
    48. }
    49. if (add[r]){
    50. update_add(lt(r),add[r]);
    51. update_add(rt(r),add[r]);
    52. add[r]=0;
    53. }
    54. }
    55. void build(int &x,int l,int r,int fa){
    56. if (l>r) return;
    57. int mid=(l+r)>>1;
    58. newnode(x,fa,a[mid]);
    59. build(lt(x),l,mid-1,x);
    60. build(rt(x),mid+1,r,x);
    61. pushup(x);
    62. }
    63. void init(){
    64. root=tot1=tot2=0;
    65. pre[root]=sz[root]=rev[root]=add[root]=key[root]=lt(root)=rt(root)=0;
    66. newnode(root,0,-1);
    67. newnode(rt(root),root,-1);
    68. for (int i = 0; i < n; ++i) {
    69. scanf("%d",&a[i]);
    70. // cout<
    71. }
    72. // cout<
    73. build(keyv,0,n-1,rt(root));
    74. pushup(rt(root));
    75. pushup(root);
    76. }
    77. void rotate(int x,int d){
    78. int y=pre[x];
    79. pushdown(y);
    80. pushdown(x);
    81. tree[y][!d]=tree[x][d];
    82. pre[tree[x][d]]=y;
    83. if (pre[y]){
    84. tree[pre[y]][rt(pre[y])==y]=x;
    85. }
    86. pre[x]=pre[y];
    87. tree[x][d]=y;
    88. pre[y]=x;
    89. pushup(y);
    90. }
    91. void splay(int r,int goal){
    92. pushdown(r);
    93. while (pre[r]!=goal){
    94. if (pre[pre[r]]==goal){
    95. pushdown(pre[r]);
    96. pushdown(r);
    97. rotate(r, lt(pre[r])==r);
    98. }else{
    99. pushdown(pre[pre[r]]);
    100. pushdown(pre[r]);
    101. pushdown(r);
    102. int y=pre[r];
    103. int d=(lt(pre[y])==y);
    104. if (tree[y][d]==r){// 不共线
    105. rotate(r,!d);
    106. rotate(r,d);
    107. }else{
    108. rotate(y,d);
    109. rotate(r,d);
    110. }
    111. }
    112. }
    113. pushup(r);
    114. if (goal==0) root=r;
    115. }
    116. int getkth(int r,int k){
    117. pushdown(r);
    118. int t=sz[lt(r)]+1;
    119. if (k==t) return r;
    120. else if (kreturn getkth(lt(r),k);
    121. else return getkth(rt(r),k-t);
    122. }
    123. void ADD(int x){
    124. // 将当前指针指向的位置的左子树去除
    125. splay(tp,0);
    126. int tmp=sz[lt(tp)]+1;
    127. splay(getkth(root,1),0);
    128. splay(getkth(root,tmp),root);
    129. tmp=keyv;
    130. keyv=0;
    131. pushup(rt(root));
    132. pushup(root);
    133. // 将去除的那棵左子树插入到末尾
    134. splay(getkth(root,sz[root]-1),0);
    135. keyv=tmp;
    136. pre[keyv]=rt(root);
    137. pushup(rt(root));
    138. pushup(root);
    139. // 打上加号
    140. splay(getkth(root,1),0);
    141. splay(getkth(root,k2+2),root);
    142. update_add(keyv,x);
    143. pushup(rt(root));
    144. pushup(root);
    145. tp= getkth(root,2);
    146. }
    147. void REVERSE(){
    148. // 将当前指针指向的位置的左子树去除
    149. splay(tp,0);
    150. int tmp=sz[lt(tp)]+1;
    151. splay(getkth(root,1),0);
    152. splay(getkth(root,tmp),root);
    153. tmp=keyv;
    154. keyv=0;
    155. pushup(rt(root));
    156. pushup(root);
    157. // 将去除的那棵左子树插入到末尾
    158. splay(getkth(root,sz[root]-1),0);
    159. keyv=tmp;
    160. pre[keyv]=rt(root);
    161. pushup(rt(root));
    162. pushup(root);
    163. // 打上逆转标号
    164. splay(getkth(root,1),0);
    165. splay(getkth(root,k1+2),root);
    166. update_rev(keyv);
    167. pushup(rt(root));
    168. pushup(root);
    169. tp= getkth(root,2);
    170. }
    171. void INSERT(int x){
    172. splay(tp,0);
    173. int t=sz[lt(root)]+2;
    174. splay(getkth(root,t),root);
    175. newnode(keyv, rt(root),x);
    176. pushup(rt(root));
    177. pushup(root);
    178. }
    179. void DELETE(){
    180. splay(tp,0);
    181. int tmp=sz[lt(root)];
    182. splay(getkth(root,tmp),0);
    183. splay(getkth(root,tmp+2),root);
    184. s[++tot2]=keyv;
    185. keyv=0;
    186. pushup(rt(root));
    187. pushup(root);
    188. if (tmp+1==sz[root]) tp=getkth(root,2);
    189. else tp=getkth(root,tmp+1);
    190. }
    191. void MOVE(int x){
    192. splay(tp,0);
    193. if (x==1){
    194. int t=sz[lt(root)];
    195. if (t==1) tp=getkth(root,sz[root]-1);
    196. else tp=getkth(root,t);
    197. }else{
    198. int t=sz[lt(root)]+2;
    199. if (t==sz[root]) tp=getkth(root,2);
    200. else tp=getkth(root,t);
    201. }
    202. }
    203. int QUERY(){
    204. splay(tp,0);
    205. return key[root];
    206. }
    207. char op[100];
    208. int x;
    209. int main()
    210. {
    211. int kase=0;
    212. while (cin>>n>>q>>k1>>k2){
    213. if (!n && !q && !k1 && !k2) break;
    214. printf("Case #%d:\n",++kase);
    215. init();
    216. tp=getkth(root,2);
    217. while (q--){
    218. scanf("%s",op);
    219. if (op[0]=='a'){
    220. scanf("%d",&x);
    221. ADD(x);
    222. }else if (op[0]=='r'){
    223. REVERSE();
    224. }else if (op[0]=='i'){
    225. scanf("%d",&x);
    226. INSERT(x);
    227. }else if (op[0]=='d'){
    228. DELETE();
    229. }else if (op[0]=='m'){
    230. scanf("%d",&x);
    231. MOVE(x);
    232. }else{
    233. printf("%d\n",QUERY());
    234. }
    235. }
    236. }
    237. return 0;
    238. }

    最后感谢博客:

    HDU 4453 Looploop(伸展树应用,数列环)_Soar-的博客-CSDN博客_hdu-4453

  • 相关阅读:
    百度智能云千帆大模型平台2.0来了!从大模型到生产力落地的怪兽级平台!!
    Java学习任务总结【17】
    微服务框架 SpringCloud微服务架构 7 Feign 7.1 基于Feign 远程调用
    自定义View3-水波纹扩散(仿支付宝咻一咻)实现代码、思想
    springboot集成redis,使用jackson序列化方案报Type id handling not implemented for 错误问题处理
    使用linux系统IO函数实现 `cp`指令的功能
    MySQL MHA
    【0108】checkpoint运行原理
    Vue:内置组件:KeepAlive(缓存组件实例)
    【Azure Power BI】Power BI获取SharePoint List列表后,如何展开List/Table中的字段,以及使用逗号拼接为一个字符串
  • 原文地址:https://blog.csdn.net/weixin_46266058/article/details/128065579