【序列之神splay】poj3580

首先借助Google大叔吧这道题看懂了。

和【noi维护数列】比较相像,可以说是其简化版本,需要维护的东西少一点,操作要多一个。

简要的来说,他是要支持者样几种操作:

     1.插入删除;

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

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

     4.一段全部增加k;

     5.询问一段的最小值。

前一段时间学习了一下Splay,亮点就在与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]:

             这个操作稍微麻烦一点,先把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。

      

 

Splay一共5种旋转,写起来稍麻烦,特判比较多,程序一下子就丑了起来,于是抱着侥幸的心理,编写了只有左旋右旋两种旋转的‘Splay’(酷似treap);编起来非常舒服,最后111行写完了,交程序的时候,AC的字样着实让我兴奋了下,下面是记录:

Run IDUserProblemResultMemoryTimeLanguageCode LengthSubmit Time
7196764cjLD3580Accepted5016K1266MSPascal2689B2010-07-19 22:13:35

 

速度是慢了点,这你别怪我,但是2689B的长度到是非常可观,真真考试的时候还是要考虑下编程复杂度的。

关于专门卡的数据也不怕,只要在每次操作后random一个数提根,还是很有效的。

 

贴代码:

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值