4270. 【NOIP2015模拟10.27】魔道研究
Description
“我希望能使用更多的魔法。不对,是预定能使用啦。最终我要被大家称呼为大魔法使。为此我决定不惜一切努力。”
——《The Grimoire of Marisa》雾雨魔理沙
魔理沙一如既往地去帕秋莉的大图书馆去借魔导书(Grimoire) 来学习魔道。
最开始的时候,魔理沙只是一本一本地进行研究。然而在符卡战中,魔理沙还是战不过帕秋莉。
好在魔理沙对自己的借还和研究结果进行了记录,从而发现了那些魔导书的精妙之处。
帕秋莉的那些魔导书,每本都有一个类别编号ti 和威力大小pi。而想要获得最有威力的魔法,就必须同时研究一些魔导书。而研究的这些魔导书就必须要满足,类别编号为T 的书的本数小于等于T,并且总共的本数小于等于一个给定的数N。而研究这些魔导书之后习得的魔法的威力就是被研究的魔导书的威力之和。
为了击败帕秋莉,魔理沙想要利用自己发现的规律来获得最有威力的魔法。
她列出了计划中之后M 次的借还事件,并想要知道每个事件之后自己所能获得的魔法的最大威力。可她忙于魔法材料——蘑菇的收集,于是这个问题就交给你来解决了。
Input
输入文件grimoire.in。
第1 行2 个整数N,M,分别表示魔理沙能研究的魔导书本数的上限和她的借还事件数。
之后M 行,每行的形式为“op t p”(不含引号)。Op 为“BORROW” 或“RETURN”,分别表示借书和还书。T 为一个整数,表示这本书的类别编号。P为一个整数,表示这本书的威力大小。注意,还书时如果有多本书满足类别编号为t,威力大小为p,这表明这些书都是相同的,魔理沙会任选其中一本书还回去。如果你问我为何会有相同的书,多半因为这是魔导书吧。
Output
输出文件grimoire.out。
一共M 行,每行一个整数,即每个事件之后的最大威力。
Sample Input
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
Sample Output
5811
10843
5811
11361
14847
9036
3486
8602
18165
18259
Data Constraint
对于5% 的数据,1 <= t,N,M <= 50。
对于10% 的数据,1 <= t,N,M <= 100。
对于30% 的数据,1 <= t,N,M<= 10 000。
另有30% 的数据,1 <= p <= 1 000。
对于100% 的数据,1 <= t,N,M <= 300 000,1<= p<= 1 000 000 000。
另外,总共有30% 的数据,满足没有“RETURN” 操作。这部分数据均匀分布。
思路
1、平衡树
平衡树支持查找树中第i大,还有招它的前驱,所以我们可以找到第i大,然后不停找前驱,这样就维护了每种系列的最大值。
然后维护包含所有序列树我们可以用动态规划(当然太麻烦,而且时间也没优化多少),所以也可以开个数组存,然后每次就一次快排,当然这样再一看数据规模,TLE,除非你的常数处理的非常好。所以我们可以再开一棵平衡树,然后和每个序列的平衡树对接,这样就比较优秀了。
而且如果用splay可以省内存,会的人都懂。。。
再jzoj这边有位同学splay跑了500多ms,而我1000多ms,orz~~~,所以平衡树还是很好用的,就是代码量大了点,300多行。当然看个人写法。
2对顶堆
(⊙o⊙)…这个博主我不会,据说差不多要成为时代的眼泪了,所以有兴趣的的同学请自行百度或谷歌。
3线段树
这个是用权值线段树,而且要动态开点,动态开点就是线段树动态开节点,也就是说我们不把那些空节点建起来,只保留那些非空的节点。
具体来说,假如说,一个用来区间求和的线段树,初始的时
候序列里所有元素都是 0, 每个节点就都是空的——全是 0。
我们就没有必要把这些空节点都建起来——最开始的时候线
段树就是空的。当我们进行修改操作时,才把这个修改所涉及的
点开出来。
比如,将 3 号位置变为 4。
我们就把根节点到 [3,3] 节点这条链建起来,并进行相应的
修改。
这样就算序列长度有 1e9 也可以线段树啦。
不过注意,动态开节点是不能堆式存储的。
权值线段树。
我们描述一个可重集合里面的元素,可以开一个以权值为下
标的数组,数组内容为对应权值的出现次数。这个数组称为权值
数组。
而用来维护权值数组的线段树,就是权值线段树。
然后,求某个权值在集合里的排名什么的,只要在线段树里
查查前缀和就知道了。
可权值范围有 1e9 怎么办?
不虚!我们可以动态开节点!
当然也可以结合离散化来更好地压缩空间和时间。
线段树二分
线段树本身就是一个二分的结构,我们没有必要外面
再套一重二分。我们可以直接在线段树上走。
比如我们现在站在线段树的某个节点 [l,r] 上,我们要求权值
在这个区间里的第 k 小元素。
假如 l = r,我们就可以直接报出答案了。
假如 l ̸= r。
我们可以先看一看这个点的左儿子——[l,mid]。假如 [l,mid]
中的元素个数 ≥ k,那第 k 小元素显然在 [l,mid] 中,我们走到
[l,mid],继续求解即可。
假如 [l,mid] 中的元素个数 < k,那么第 k 小元素显然在
[mid+1,r],也就是右儿子中。我们令 k:=k-[l,mid] 中的元素个数,
走到 [mid+1,r],继续求解即可。
这样复杂度是 O(nlogn) 的。
类似地,前 k 小元素的权值和,还有第 k 大,前 k 大之类的
问题都可以这么解决。
“我们有若干个可重集合,然后我们从第 i 个可重集合中拿前
i 大组成一个新的可重集合 S。我们的目的是动态维护 S 的前 n
大的和。”
显然,我们需要维护所有的小集合以及 S。
维护 maxt 棵权值线段树,第 i 棵线段树对应第 i 个小集合。
我们称这些线段树为小树。
另外维护一棵权值线段树,用来维护 S。我们称这棵线段树
为大树。
对于 BORROW 操作,我们就是在第 t 棵小树中加入一个元
素 p。这个可以通过线段树单点修改完成。
之后,我们要确定要不要将 p 加入 S 中。这个只要知道 p
在第 t 个集合中的排名是否 ≤ t 即可。
加入了 S 以后,我们还要将原来的第 t 大,即现在的第 t+1
大从 S 中删去。
对于 RETURN 操作,我们可以类似地,将 BORROW 操作
取反即可。
而动态维护 S 前 n 大的和自然也是小菜一碟了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<set>
#include<deque>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define M 300007
#define K 1000000007
#define N 100000
using namespace std;
typedef long long LL;
int i,j,k,l,tt,n,m,p,num;
LL ans,ans1,ans2;
int di[M];
struct node{int tot,l,r;LL sum;
}t[M*100];
char aa[7];void dikda(int x,int l,int r,int z){if(l==r){ans1=l;return;}int mid=(l+r)/2;if(t[t[x].r].tot>=z)dikda(t[x].r,mid+1,r,z);else dikda(t[x].l,l,mid,z-t[t[x].r].tot);
}
void get(int x,int l,int r,int z){if(l==r){ans=ans+min(t[x].tot,z)*l;return;} int mid=(l+r)/2;if(t[t[x].r].tot>=z)get(t[x].r,mid+1,r,z);else get(t[x].l,l,mid,z-t[t[x].r].tot),ans+=t[t[x].r].sum;
}
int main(){freopen("grimoire.in","r",stdin);freopen("grimoire.out","w",stdout);scanf("%d%d",&n,&m);fo(i,1,m){scanf("%s%d%d",aa,&tt,&p);if(aa[0]=='B'){if(t[di[tt]].tot>=tt){dikda(di[tt],1,K,tt);}else ans1=0;if(p>=ans1){insert(di[0],1,K,p);if(ans1>0)delet(di[0],1,K,ans1);}insert(di[tt],1,K,p);}else{if(t[di[tt]].tot>tt){dikda(di[tt],1,K,tt+1);}else ans1=0;if(p>=ans1){delet(di[0],1,K,p);if(ans1>0)insert(di[0],1,K,ans1);}delet(di[tt],1,K,p);}ans=0;get(di[0],1,K,n);printf("%lld\n",ans);}
}
4270. 【NOIP2015模拟10.27】魔道研究相关推荐
- jzoj4270 [NOIP2015模拟10.27]魔道研究 线段树
Description "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力." --<The Grimoire of Mar ...
- [NOIP2015模拟10.27] [JZOJ4270] 魔道研究 解题报告(动态开点+权值线段树上二分)
Description "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力." --<The Grimoire of Mar ...
- 【NOIP2015模拟10.27】魔道研究
Description "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力." --<The Grimoire of Mar ...
- jzoj4270. 【NOIP2015模拟10.27】魔道研究
题目描述 Description "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力." --<The Grimoire o ...
- 【JZOJ B组】【NOIP2015模拟10.27】魔道研究
Description "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力." --<The Grimoire of Mar ...
- 2018.07.12【2018提高组】模拟B组 【NOIP2015模拟10.27】魔道研究
#Description "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力." --<The Grimoire of Ma ...
- 【NOIP2015模拟10.27】魔道研究题解
改了这么久,终于把这道题A了,我太弱了 感谢ZLZ巨佬的教导以及CZC帮忙调试. 来写一篇题解吧. Description "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼 ...
- 2018.07.12【2018提高组】模拟B组 【NOIP2015模拟10.27】魔法阵
#Description 帕秋莉·诺蕾姬,有着"不动的大图书馆" 的称号,擅长使用各种各样的属性魔法. --<东方求闻史记> 一如既往地,帕秋莉在图书馆中研究着魔法.今 ...
- jzoj4271. 【NOIP2015模拟10.27】魔法阵
题目描述 Description 帕秋莉·诺蕾姬,有着"不动的大图书馆" 的称号,擅长使用各种各样的属性魔法. --<东方求闻史记> 一如既往地,帕秋莉在图书馆中研究着 ...
最新文章
- 现在没点硬核技术都不敢卖货了
- python 代理使用方法简介
- python横向柱状图-python绘制横向水平柱状条形图Bar
- 腾讯TEG校招群聊天记录曝光,速来围观!
- IP多播技术及其应用
- java httpclient 重定向_如何在HttpClient中自动重定向(java,apache)
- (转) shiro权限框架详解06-shiro与web项目整合(上)
- angularjs 服务详解
- docker镜像的常用操作
- 定制家具设计拆单用什么软件好?
- 最新emoji表情代码大全_微信表情包大全 百度输入法让你斗图斗到爽
- 购物直播APP系统+短视频系统开发方案
- Java软件开发工程师简历模板包装教学问题完整版 【心静思远-9527】
- input隐藏域传值给后台
- (转帖)ConcurrentHashMap实现原理(3)
- Hadoop Web 控制台安全认证
- .Net Core学习笔记(二)MVC框架
- latex 分页_latex 排版 首页不会换页
- 黑马程序员 方立勋JavaWEB视频 第2、3天 xml笔记
- 自学编程之路(自我记录)
热门文章
- Android挂逼修炼之行---微信摇骰子和猜拳作弊器原理解析
- 《共同利益经济学》让梯若尔 epub+mobi+azw3
- 网易云音乐.uc格式的缓存文件转.mp3
- 倒序存放数组java_java 将一个数组逆序输出的方法
- 在PHP中如何使用Predis
- java tts开源,程序员罗杰-开源的TTS软件Flite从安装到使用
- 零基础自学软件测试,第一份外包工作8K,到现在大厂月薪25K*16薪
- EMOTIV Epoc X 无线便携式脑电仪
- 计算机一级ppt定位,课件全国计算机一级基础知识.ppt
- 如何才能实现自己的梦想