数据结构刷题合集

一P4113 [HEOI2012]采花

这是一个求一个区间出现次数大于等于二的数字的个数

这个的思路其实十分的的人类智慧,首先我们不难想到把所有的操作离线下来,之后就可以把复杂度降低了,之后就考虑一下如何去问维护信息,首先我们可以考虑前缀和,也就是参考HH的项链那道题,我们对于每一个color记录一下上一个出现的位置last1,之后假如再次出现就给上一个位置那里加一

这里不直接给第二次的位置加一是因为,考虑223这个序列,假如查询(2,3) ,就会出问题。

之后我们发现还有可能出现三次,这个假如像之前处理就显然是错误的,所以我们考虑再加一个数组last2,存第二次出现的位置

之后对于一个数字假如说第三次出现就给第一次出现的位置-1,第二次出现的位置加一,最后求和就好了

为什么正确

首先假如对于一个区间(l,r)给这个区间每一个数加一,那么我想你们都会做,也即是前缀和。

那么考虑这题,

一。(l,r)是一个数字出现的两个位置,是不是之后所有包含这个区间的查询都得到他的贡献,所以我们只给l的位置加一显然是正确的

二。(l,r,z)是一个数字出现的三个位置,那么我们考虑给r+1,l-1,那么所有左端点(l,r)的一定可以统计这次贡献,之后同理

二P4198 楼房重建

这是一道超级无敌大好题,不单是一个数据结构,而且思维也不错

首先考虑我们要求的是什么,斜率的最长上升长度,这个走暴力显然是超时的,之后我们就去看一下其实也是维护一个序列,用啥呢,平衡树?不可能啊,树状数组?这个max也不满足区间可减性,线段树?貌似可

那就先考虑线段树维护什么1.肯定是ans 2.是不是还要维护一个ans 之后还要什么吗? 不晓得,那就先想一想区间的合并

考虑左右两个儿子如何去给父亲提供帮助,max肯定就是两者的max取max,那么ans呢,我们想一下,左儿子的ans是不是直接传上去就ok了,那么右儿子的呢,是不是要去找从左开始比左兄弟max大的个数,这是不是可以合并,之后就是查询这个比max大的值

查询——》 首先还是要考虑左右儿子,假如说左儿子的最大值比这个小,那么我们是不是就放弃左儿子,去找右儿子。那假如比这个大呢?我们是不是就去找左儿子和右儿子,等等这个复杂度是不是稍微有一点问题,很明显这个就不满足线段树可以分支的这个省时间的套路,所以要优化

优化——》左儿子的递归查询是不可避免的,那么就在右儿子上做一下文章,这个区间的ans是不是在之前就确定好了,这个ans = 左儿子的ans + 右儿子比左儿子max的数目,等等,是不是这个区间的ans减去左儿子的ans就可以找到右儿子的贡献,因为比左兄弟的max还大的数肯定比查询的值要大,而比左兄弟max小的数是不是无论如何都无法统计,所以是不是就优化完成了

三P5278 算术天才⑨与等差数列

细节十分的多,其实也是很多的

首先发现这道题感觉做法应该挺多的,但是我们由于是再考虑数据结构。那就看看我们要维护的信息是啥对吧

首先要是需要满足是一个等差数列,是不是是很自然的就想到了维护区间max和min,那么是不是区间max - min = k * ( r - l)。这只是第一个判断,这样显然是不够用的,之后看看是不是还要每个数字的差都含有k这个因子,也就是维护查分序列的gcd%k == 0,这样够吗?是不是还是有重复数字的可能性,之后就不是维护一下每一个数字上一次出现的位置,是这个区间前驱位置的max < l 是不是就完美了。

首先看一看平衡树可以维护吗?好像没问题,但是写起来好像有点烦,那先看看线段树? 那就考虑一下区间是否可以合并,首先gcd,pre,max ,min是不是都是可以合并的,所以是不是写线段树就好了,之后是不是貌似好了,之后最大的问题就是修改和找前驱,这也是这道题个我的启发

启发

1.找一个数字上一次出先的位置,并且还要知道下一次出先的位置(修改时要用),我们就可以用map给每一个数字一个编号(节约空间),之后每一个编号上开一个set(记得最开始初始化插入0, n + 1),每一次就可以lower_bound直接查询,完美!!

2.修改时要细心,考虑一下情况 首先原来的数字的后继那个位置的pre是不是要改,这个位置的pre,max…是不是也要改,之后前一个位置的差分gcd是不是也要改(我写的差分是a[l] - a[l +1])。

loj#6029. 「雅礼集训 2017 Day1」市场

要维护区间除下取整,区间加,区间max,区间和

最难的肯定是区间减,假如说我们直接去区间和除这个数,那么考虑一下肯定是不对的,之后就像一下如何去维护这个区间除法

我们去维护区间的最小值和最大值,每一次除以d,假如说max / d == min / d那么这个区间的每一个数的变化量都是这个(证明在下),就直接变成区间减就好了。之后假如不等,那么我们就去向下递归,这个就会有一个复杂度的均摊

复杂度:首先每一次不等于时候向下传递最多使得log个节点的区间max-min最小减半,之后我们每一个区间max-min最多会被更改 log109 次后就会变成1,所以说复杂度就是(m+n)lognlog10 9

证明

最小值t 要除以d
则减小的就是t/d 之后每一次t++,那么这个t/d只会加1要不就不加,不加是不是就会线下递归,加的话就是直接变化对吧,其实好像之后d-1,d可成立。

启示

对于区间的除法,可以考虑看看区间的变化是不是都一样,也就是通过维护区间的maxmin来看,假如一样就直接变成区间减法就好了

类似于一次会使很多数的变小的值很大的操作其实都可以想一下变化率。

P7447 [Ynoi2007] rgxsxrs

超级无敌大毒瘤 写死我了

这道题的难度可以说时和上面的不是一个等级,所以说单独开一张

传送门

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值