JZOJ2018.07.12【2018提高组】模拟B组 魔道研究

 

4270. 【NOIP2015模拟10.27】魔道研究 

题目描述

“我希望能使用更多的魔法。不对,是预定能使用啦。最终我要被大家称呼为大魔法使。为此我决定不惜一切努力。”

 

——《The Grimoire of Marisa》雾雨魔理沙
魔理沙一如既往地去帕秋莉的大图书馆去借魔导书(Grimoire) 来学习魔道。
最开始的时候,魔理沙只是一本一本地进行研究。然而在符卡战中,魔理沙还是战不过帕秋莉。
好在魔理沙对自己的借还和研究结果进行了记录,从而发现了那些魔导书的精妙之处。
帕秋莉的那些魔导书,每本都有一个类别编号ti 和威力大小pi。而想要获得最有威力的魔法,就必须同时研究一些魔导书。而研究的这些魔导书就必须要满足,类别编号为T 的书的本数小于等于T,并且总共的本数小于等于一个给定的数N。而研究这些魔导书之后习得的魔法的威力就是被研究的魔导书的威力之和。
为了击败帕秋莉,魔理沙想要利用自己发现的规律来获得最有威力的魔法。

 

她列出了计划中之后M 次的借还事件,并想要知道每个事件之后自己所能获得的魔法的最大威力。可她忙于魔法材料——蘑菇的收集,于是这个问题就交给你来解决了。

输入

第1 行2 个整数N,M,分别表示魔理沙能研究的魔导书本数的上限和她的借还事件数。

之后M 行,每行的形式为“op t p”(不含引号)。Op 为“BORROW” 或“RETURN”,分别表示借书和还书。T 为一个整数,表示这本书的类别编号。P为一个整数,表示这本书的威力大小。注意,还书时如果有多本书满足类别编号为t,威力大小为p,这表明这些书都是相同的,魔理沙会任选其中一本书还回去。如果你问我为何会有相同的书,多半因为这是魔导书吧。

输出

一共M 行,每行一个整数,即每个事件之后的最大威力。

样例输入

 

5 10 
BORROW 1 5811 
BORROW 3 5032
RETURN 3 5032 
BORROW 3 5550 
BORROW 5 3486 
RETURN 1 5811 
RETURN 3 5550 
BORROW 4 5116 
BORROW 3 9563 
BORROW 5 94

输出

 

5811
10843
5811
11361
14847
9036
3486
8602
18165
18259

 

没办法,太久没写博客了,第三题又没A,只好来BB第二题了。

要A第二题,要先知道一个东西——权值线段树

为什么这题需要权值线段树?先看看题目大意

给你一些数以及它所在的集合的编号,从每个集合中选不超过t(这个集合的编号)个数,组成一个大集合,再求大集合中前N大个数的和。

很明显t个数必须是小集合中最大的,否则不满足要求

前T大?前N大?权值线段树就能做到。

(注:下文小树即小集合,大树即大集合)

有的同学可能会想t<=300000,p<=1000000000,

权值线段树开那么大不会爆空间么?

不怂,咱有动态开点。

诶,打住,什么是动态开点?

-------------------------------------------------------------分割线--------------------------------------------------------------

先讲动态开点的原理

有时我们会发现,一棵权值线段树中可能有很多节点都是空的,因为一个数只能修改log n个点(如下图),于是就造成了极大的空间浪费。

但你没必要在一开始就开那么大的空间

如果读入一个数只改变一条链(如1,4->3,4->4,4),就只需要log n个节点。

如果我们把总子节点数存下来,再记下每个节点的左右儿子与这个区间有多少个数(如上图(1,4)有1个数,即4,则这个区间有一个数)就可以省下很大空间。

但300000棵权值线段树空间还是太大了,怎么办?

没关系,我们只需要记下每棵权值线段树根节点的编号,然后递归时沿着左右儿子走就行了。

如果没有这棵线段树,新开一棵即可。

---------------------------------------------------------分割线------------------------------------------------------------------

建树明白了,那么怎么查找维护呢?

二分即可,权值线段树只要顺着左右儿子走就能满足二分。

接下来讲B(BORROW),R(RETURN)操作

B操作:

由于B操作会给第ti棵权值线段树加入一个数,所以树上原来第ti大的数可能改变,

因此要在加数的同时带一个参数,表示当前树上有多少个数比要加入的这个数大,

如果它小于ti,就说明它是前ti大的(在当前权值线段树中),那么就需要加入大树(即最终计算答案的权值线段树)

但新加入的数可能是第ti大的,所以原来的第ti大的数会被挤出前ti名,所以需要把它从大树中删除。

于是再加两个递归,一个寻找第ti棵树上的第ti+1大的数,一个删除数。

很明显如果一棵树上不足t 个数就不会有第ti+1大,记录一下树上有多少个数即可。

至于删数与加数的操作差不多,这里不多讲。

R操作:

R操作与B操作相反,需要删数,所以将它与删大树上的数的递归结合在一起打,记录一下被删除数在小树上的排名,

如果是前ti名则将它从大树中删去,再在小树中寻找新的第ti名加入大树,记得更新树上的数的数量。

至于计算答案:

可以记录第i棵子树上的数的和,然后的处理跟区间查询差不多。

至此结束。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值