【pku3580】SuperMemo(Splay维护区间信息)

一向对数据结构不感冒,这次有所改观

盾哥对SPLAY 的崇拜使我也开始对这种感觉还比较好用的数据结构产生了兴趣

先分析下SPLAY的特点:

      1.它能维护一个序列,动态地支持一些操作(主要是区间型操作),任意时刻它的中序遍历都是当前序列,这棵树其实是以位置为“序”的

      2.它可以通过提根操作完成区间型操作,这里要用到类似与线段树的LAZY标记,更基本的操作就是旋转

      3.可扩展性非常好,支持非常多的操作,感觉上线段树能搞定的,splay基本上都没什么问题

      4.它的常数因子非常大,O(logN)真的只是“理论”复杂度

      5.标准的splay有一大堆旋转和一大堆特判,编程复杂度奇高无比,其实不实用。个人感觉裸提根(就是只用朴素的左旋右旋)也还不错,对于编程速度要求很高的各大oi比赛中,较低的编程复杂度可能会更合适

      6.初始的建树如果想偷懒就直接建成一条链,然后一顿乱旋几下,而要求高点可能就要建成一棵完全二叉树了

      7.由于每个点携带的信息不多,空间上比线段树什么的稍微好点

大概就这样吧,可以看到,splay还是相当不错的,下面接着看这道题

题目大意:

     维护一个序列,支持下列操作:

    1.插入删除;

     2.翻转一段选定的序列;

     3.交换两段相邻的序列;

     4.一段全部增加k;

     5.询问一段的最小值。

分析:

     看到一大堆的操作就应该想到是到数据结构题,由于要完成区间型操作,可以会先想到线段树,但动态的插入和删除貌似用线段树不好搞定,怎么办?splay这种强大的数据结构便能让我们脱离苦海,驶向ac的彼岸

算法:

     用splay维护这个序列(先搞个极小极大点),对于每个操作:

     1.插入 j 到 i 后面:

       首先把i提根,在新建节点 j,使得r[j]=r[i];r[i]=j; 再维护j,i的信息即可;

     2.删除i:

       首先把i提根,再把 i+1提根,接着把 l[i+1]=l[i],维护i+1,这样 i 就被删除了;

     3.翻转(增加)区间[a,b]:

       先把a-1提根,再把b+1提根,这时候,以r[l[root]]就是我们要的区间,再用线段树的lazy思想,把标记放上去并维护就可以了;

     4.交换相邻两段序列[a,b],[b+1,c](所谓的revolve其实就是这个,自己想一想):

       这个操作稍微麻烦一点,先把b提根,再把a-1提为b的左儿子,接着把c+1提为b的右儿子,这时把l[r[root]](即区间[b+1,c])作为l[root]的右儿子,而原来的右儿子作为root的左儿子。此时发现root和原来的l[root]这颗子树断开连接了,我们需要把此时以root为根的树的最小的点提出来作为根,再把原来的l[root]置为 root‘ 的左儿子,操作完成。

    编写的时候还是出现了一些问题的,要不会像盾哥一样调到晚上一点多(结果第二天迟到了),如:

           1.min数组在标记下放的是后可以同加同减,不用再从下面更新了,更新也是错的。

           2.标记下方完后清空。

           3.因为一开始就新建了n+2个点,所以记总点数一开始即为n+2

    好了,只用了145行就搞定,而且交这道题时是1遍ac,小小的爽了一把。

代码:

 

 

一题一结构,无题不算法

 

 

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值