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. 将问题转换成求两个日 ...
随机推荐
- sqlserver数据库附加报错5120
sqlserver数据库的数据文件分离.附加是很方便的功能. 有时候在附加文件时报错,是因为数据库文件权限不够,给Authenticated Users用户增加完全控制权限即可.
- JsonHelper
.net下的json序列化在以前没有Newtonsoft.Json崭露头角之前采用System.Web.Script.Serialization命名空间下的JavaScriptSerializer对象 ...
- 错题726-java
class Car extends Vehicle { public static void main (String[] args) { new Car(). run(); } private fi ...
- usb驱动开发1之学习准备
此系列是http://blog.csdn.net/fudan_abc/博文的整理,同时加入了自己的理解.很敬佩fudan_abc的文章,仔细学习和分析受益很多.注:fundan_abc所分析linux ...
- C语言 日常小结
1.当数组当作函数参数的时候会退化为指针 #include<stdio.h> #include<stdlib.h> void sort(int a[]){ int num = ...
- char 转wchar_t 及wchar_t转char
利用WideCharToMultiByte函数来转换,该函数映射一个unicode字符串到一个多字节字符串.通常适合于window平台上使用. #include <tchar.h> #in ...
- Java获取客户端IP
在开发工作中,我们常常需要获取客户端的IP.一般获取客户端的IP地址的方法是:request.getRemoteAddr();但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实 ...
- LeetCode:Unique Binary Search Trees I II
LeetCode:Unique Binary Search Trees Given n, how many structurally unique BST's (binary search trees ...
- 学习笔记——Maven实战(七)常用Maven插件介绍(上)
我们都知道Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven-compiler-plugin完成的.进一步说,每个任务对应了 ...
- ASP.NET MVC5 插件化机制简单实现
一.前言 nopCommerce的插件机制的核心是使用BuildManager.AddReferencedAssembly将使用Assembly.Load加载的插件程序集添加到应用程序域的引用中.具体 ...