hihocoder #1034 毁灭者问题
描述
在 Warcraft III 之冰封王座中,毁灭者是不死族打三本后期时的一个魔法飞行单位。
毁灭者的核心技能之一,叫做魔法吸收(Absorb Mana):
现在让我们来考虑下面的问题:
假设你拥有 n 个魔法单位,他们从左到有站在一行,编号从 1 到 n。 每个单位拥有三项属性:
si: 初始法力。
mi: 最大法力上限。
ri: 每秒中法力回复速度。
现在你操纵一个毁灭者,有 m 个操作,t l r,表示时刻 t,毁灭者对所有编号从 l 到 r 的单位,使用了魔法吸收。操作按照时间顺序给出,计算毁灭者一共吸收了多少法力。
输入
输入数据的第一行有一个整数 n (1 ≤ n ≤105) — 你的魔法单位的数目。
接下来的 n 行,每行有三个整数 si, mi, ri (0 ≤ si ≤ mi ≤ 105, 0 ≤ ri ≤ 105) 描述一个魔法单位。
接下来一行又一个整数 m (1 ≤ m ≤ 105), — 操作的数目。
接下来的 m 行,每行描述一个操作 t, l, r(0 ≤ t ≤ 109, 1 ≤ l ≤ r ≤ n),t 非降。
输出
输出一行一个整数表示毁灭者一共吸收了多少法力。
- 样例输入
-
5
0 10 1
0 12 1
0 20 1
0 12 1
0 10 1
2
5 1 5
19 1 5 - 样例输出
-
83
Solution:
如果魔法单位没有法力上限,这道题就是一道水题了,线段树即可搞定。
设置了法力上限,从维护区间的角度来考虑就比较困难了。
我们换一种思路,考虑对每一个魔法单位维护其遭遇收割的各个时刻,或者说其遭遇收割的时间序列(以下简称“时间序列”)。
这样就可以轻松求出毁灭者在各个魔法单位收割的法力值,做法如下:
为简单计,先假设所有魔法单位的初始法力都为零。
设魔法单位 $i$ 法力回满所需时间为 $T$,显然 $T=\lceil \frac{m_i}{r_i}\rceil$ 。
考察相邻收割时刻 $t_k$与$t_{k+1}$,其间隔记做 $\Delta t=t_{k+1}-t_{k}$,若 $\Delta t<T$ 则$t_{k+1}$ 时刻收割的法力值为 $\Delta t\times r_i$,否则为 $m_{i}$ 。
对于每个魔法单位我们只要知道其遭遇收割的时间间隔(以下简称“时间间隔”)中,大于等于$T$的时间间隔的个数以及小于 $T$ 的时间间隔的总和。
对每个魔法单位,我们可以用 map 来维护其遭受收割的时间序列,用树状数组来维护时间间隔之和与时间间隔的数量之和。
对每个魔法单位都按上述方式做一遍,时间上不能承受。同时应当注意到相邻魔法单位的时间序列是有联系的,可以动态维护
假设现在已经维护好了第 $i$ 个魔法单位的时间序列和时间间隔,在此基础上去掉所有以 $i$ 为区间右端点的收割时刻,再插入所有以 $i+1$ 为区间左端点的收割时刻,就得到了第 $i+1$ 个魔法单位的时间序列。
删除一个时刻 $t_{i}$ 意味着删除了两个时间间隔 $t_{i}-t_{i-1}$ 和 $t_{i+1}-t_{i}$,新增了一个时间间隔 $t_{i+1}-t_{i-1}$;插入一个时刻 $t_{i}$ 的作用恰好相反。
Implementation:
对每个魔法单位,先维护出以其为左端点和右端点的收割操作。然后从左到右动态维护各个魔法单位的时间序列,同时记录下相应的时间间隔的插入与删除操作。
对涉及到的所有时间间隔进行离散化。然后对每个魔法单位,先将其对应的(或称“贡献的”)时间间隔的插入与删除操作更新到树状数组中。
最后查询两类时间间隔贡献的法力加到答案中。
另外还要考虑到初始法力值可能不为零,这并不会带来什么困难,只要算一下毁灭者在每个魔法单位第一次吸收的法力的实际值和假设初始法力为零的情况之差,加到答案里去。
复杂度 $O((m+n)\log m)$
#include <bits/stdc++.h>
using namespace std; const int N(1e5+);
typedef long long LL; LL bit[N<<];
int a[N], m[N], r[N], bit2[N<<];
vector<int> Lt[N], Rt[N], op[N], b;
map<int,int> s; void add(int x, int v, int n){
for(; x<=n; bit[x]+=v, x+=x&-x);
} LL sum(int x){
LL res=;
for(; x; res+=bit[x], x-=x&-x);
return res;
} void Add(int x, int v, int n){
for(; x<=n; bit2[x]+=v, x+=x&-x);
} int Sum(int x){
int res=;
for(; x; res+=bit2[x], x-=x&-x);
return res;
} int main(){
int n, q;
scanf("%d", &n);
for(int i=; i<=n; i++) scanf("%d%d%d", a+i, m+i, r+i);
scanf("%d", &q);
for(int l, r, t; q--; ){
cin>>t>>l>>r;
Lt[l].push_back(t);
Rt[r].push_back(t);
}
s[]++;
LL ans=;
for(int i=; i<=n; i++){
for(auto &t: Rt[i-]){
if(--s[t]) continue;
auto p=s.lower_bound(t);
int pre, suc;
pre=(--p)->first, ++p, op[i].push_back(pre-t);
if(++p!=s.end())
suc=p->first, op[i].push_back(t-suc), op[i].push_back(suc-pre), b.push_back(suc-pre);
s.erase(--p); //error-prone
}
for(auto &t: Lt[i]){
if(s[t]++) continue;
auto p=s.lower_bound(t);
int pre, suc;
pre=(--p)->first, ++p, op[i].push_back(t-pre), b.push_back(t-pre);
if(++p!=s.end()) suc=p->first, op[i].push_back(suc-t), b.push_back(suc-t), op[i].push_back(pre-suc);
}
if(s[]>) ans+=a[i];
else{
auto p=s.begin();
if(++p!=s.end()){
int t=p->first;
ans+=min(a[i]+(LL)t*r[i], (LL)m[i])-min((LL)t*r[i], (LL)m[i]); //error-prone
}
}
}
sort(b.begin(), b.end());
auto e=unique(b.begin(), b.end());
int size=e-b.begin();
for(int i=; i<=n; i++){
for(int &x: op[i]){
int id=upper_bound(b.begin(), e, abs(x))-b.begin(); //error-prone
add(id, x, size);
if(x<) Add(id, -, size);
else Add(id, , size);
}
if(m[i]== || r[i]==) continue; //error-prone
int t=(m[i]-)/r[i]+;
int id=lower_bound(b.begin(), e, t)-b.begin();
ans+=(LL)(Sum(size)-Sum(id))*m[i];
ans+=sum(id)*r[i];
}
printf("%lld\n", ans);
return ;
}
代码中坑主要有
(1)注意需要用long long的地方
(2)别忘了将时刻从map中删除(代码第52行)
s.erase(--p); //error-prone
对拍才发现跪在这里的,多么痛的领悟。。。静态查错很重要啊。。。。。。。。。。。
hihocoder #1034 毁灭者问题的更多相关文章
- hihocoder #1034 : 毁灭者问题 平衡树(set)+线段树
#1034 : 毁灭者问题 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在 Warcraft III 之冰封王座中,毁灭者是不死族打三本后期时的一个魔法飞行单位. 毁 ...
- hihoCoder Challenge 1
#1034 : 毁灭者问题 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在 Warcraft III 之冰封王座中,毁灭者是不死族打三本后期时的一个魔法飞行单位. 毁 ...
- hihoCoder挑战赛1 毁灭者问题
题目链接:http://hihocoder.com/problemset/problem/1034 数据结构题,由于每个魔法单位有着不同的回复速度和上限,所以不能根据吸收时间点进行查询和更新.但是如果 ...
- hihocoder -1121-二分图的判定
hihocoder -1121-二分图的判定 1121 : 二分图一•二分图判定 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 大家好,我是小Hi和小Ho的小伙伴Net ...
- Hihocoder 太阁最新面经算法竞赛18
Hihocoder 太阁最新面经算法竞赛18 source: https://hihocoder.com/contest/hihointerview27/problems 题目1 : Big Plus ...
- hihoCoder太阁最新面经算法竞赛15
hihoCoder太阁最新面经算法竞赛15 Link: http://hihocoder.com/contest/hihointerview24 题目1 : Boarding Passes 时间限制: ...
- 【hihoCoder 1454】【hiho挑战赛25】【坑】Rikka with Tree II
http://hihocoder.com/problemset/problem/1454 调了好长时间,谜之WA... 等我以后学好dp再来看为什么吧,先弃坑(╯‵□′)╯︵┻━┻ #include& ...
- 【hihocoder#1413】Rikka with String 后缀自动机 + 差分
搞了一上午+接近一下午这个题,然后被屠了个稀烂,默默仰慕一晚上学会SAM的以及半天4道SAM的hxy大爷. 题目链接:http://hihocoder.com/problemset/problem/1 ...
- 【hihoCoder】1148:2月29日
问题:http://hihocoder.com/problemset/problem/1148 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 思路: 1. 将问题转换成求两个日 ...
随机推荐
- Linux下利用CGroup控制CPU、内存以及IO的操作记录
CGroup及其子系统的介绍在这里就不赘述了,可以参考:Linux下CGroup使用说明梳理废话不多说,这里记录下利用CGroup控制CPU.内存以及IO的操作记录: libcgroup工具安装这里以 ...
- 安卓版微信内置浏览器,<a href="tel:电话号码"></a> 这个链接失效,不能跳到拨号界面?
https://segmentfault.com/q/1010000000318831 在URL最后面加“ #mp.weixin.qq.com ”,应该加其他qq.com的二级域名都行,估计是微信的安 ...
- P1195 口袋的天空
P1195 口袋的天空 题目背景 小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空. 有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖. 题目描述 给你云朵的个数N,再给你M个关 ...
- 不支持一个 STA 线程上针对多个句柄的 WaitAll
[csharp] view plaincopy using System; using System.Collections.Generic; using System.Windows.Forms; ...
- [shell]. 点的含义
. 的含义 当前目录 隐藏文件 任意一个字符 生效配置文件
- 【原创】Junit4详解一:Junit总体介绍
Junit是一个可编写重复测试的简单框架,是基于Xunit架构的单元测试框架的实例.Junit4最大的改进是大量使用注解(元数据),很多实际执行过程都在Junit的后台做完了,而且写test case ...
- 面试准备(二) 绘制 Activity 的生命流程图
我们来看一下这一张经典的生命周期流程图: 相信不少朋友也已经看过这个流程图了,也基本了解了Activity生命周期的几个过程,我们就来说一说这几个过程. 1.启动Activity:系统会先调用onCr ...
- ios 指南针
指南针图片 IBOutlet UIImageView *compassView 1 #import "ViewController.h" #import <CoreLoca ...
- [CareerCup] 9.4 Subsets 子集合
9.4 Write a method to return all subsets of a set. LeetCode上的原题,请参见我之前的博客Subsets 子集合和Subsets II 子集合之 ...
- 实验二实验报告 20135324&&20135330
北京电子科技学院(BESTI) 实 验 报 告 课程: 深入理解计算机系统 班级: 1353 姓名: 杨舒雯 张若嘉 学号: 20135324 20135330 成绩: 指导教师: 娄嘉鹏 实验日期: ...