szsy noip专题 数据结构进阶

并查集

这道题目说的是有N件商品,每个商品有利润pi和过期时间di,每天只能卖一个商品,过期商品不能卖,求如何安排每天卖的商品,可以使收益最大。

这道题目有两种解法:

1)二叉堆解法

方法是初始建一个为空的小根堆,设定节点的值为商品的利润,分两种情况进行讨论:①商品数量大于堆顶,元素替换小根堆顶,②商品数量不足,将元素放入这个堆即可,最后输出结果。算法的时间复杂度是O(NlogN)STL 里priority_queue是一个大根堆的操作。

2)并查集解法

使用贪心策略,优先考虑卖出利润大的商品,将商品按照利润从大到小排序,并建立一个关于天数的并查集,每一天构成一个集和。对于每一个商品,若它在d天之后过期,就在并查集中查询d的树根(记为r)。若r大于0,则把该商品安排在r天卖出,合并r和r-1,累加到最后就是该商品的利润。整体上维护一个数组中“位置”的占用情况,利用并查集的路径压缩可以快速找到最晚能卖出的时间,即从过期时间往前数第一个空闲的天数。

树状数组

这里预备知识要知道 lowbit(R),其基本用途是维护序列的前缀和。对于给定的序列a,我们建立一个数组c,其中c【x】保存序列a的区间【x-lowbit(x)+1,x】,即可以看成如下的树形结构。

                                          

树状数组支持两种基本操作,第一个操作是查询前缀和,当要计算【l,r】中所有数的和,只需要计算ask(r)-ask(l-1);

第二个操作是单点增加,给序列中的a【x】加上y,同时正确维护序列的前缀和。

这道题目的题意是有n头奶牛,已知每头奶牛的具体身高,现在这n头奶牛站成一列,已知第i头奶牛前面有Ai头比它低,求每头奶牛的身高。

我们倒序来看这道题目,如果最后一头奶牛前面有An头比他低,那么它的身高显然是Hn=An+1

如果倒数第二头奶牛的前面有An-1头牛比它低,那么:

1)若An-1<An,则它的身高Hn-1=An-1 + 1

2)若An-1≥An,则它的身高是Hn-1=An-1 + 2

按照这样逻辑进行递推,如果第k头牛前面有Ak头比它低,那么它的身高Hk是数值1~n中第Ak+1小的没有在{Hk+1,Hk+2,...,Hk}中出现的数。

具体来说设置一个01的序列b,起初全部都是1.然后从n到1倒序扫描每个Ai,对每个Ai执行以下两个操作

1)查询序列b中第Ai+1个1在什么位置,这个位置号就是第i头奶牛的身高Hi

2)把b[Hi]减1(从1变为0)

也就是说,维护一个01序列,支持查询第k+1的位置,以及修改序列中的数值

一共有两种方法进行这个操作:

1)树状数组+二分

用树状数组c维护01序列b的前缀和,在每次查询时继续二分答案,通过ask(mid)即可得到前mid个数中有多少个1,与k比较大小,即可确定二分的上下界变化。

2)树状数组+倍增

用树状数组c维护01序列b的前缀和,在每次查询时:

1.初始化两个变量ans=0和sum=0

2.从log(向下取整)到0倒序考虑每个整数p

ans+2^{p}\leq n且 ,则领  且sum+c[ans+2^{p}]< k,且令sum+c[ans+2^{p}]ans+=2^{p}

3.最后,Hi=ans+1即为答案

 

线段树

线段树是一种基于分治思想的二叉树结构

根据gcd的原理,我们可以知道gcd(x,y)=gcd(x,x-y),并且可以进一步扩展到gcd(x,y-x,z-y)

构造一个新的数列B,其中B[i]=A[i]-A[i-1] ,用线段树维护序列B的最大公约数

Qlr 就等于求出gcd(A[l],ask(1,l+1,r))

Clrd,只有B[l]加了d,B[r+1]被剪掉了d,所以在维护B的线段树上只需要两次单点修改即可。

询问时需要数列A中的值,可以额外用一支持“区间增加、单点查询”的树状数组对A进行维护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值