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. 将问题转换成求两个日 ...
随机推荐
- Java虚拟机工作原理详解 (一)
一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了解java程序工作原理.首先,你写好java代码,保存到硬盘当中.然后你在命令行中输入 javac YourClassNam ...
- python案例-用户登录
要求: •输入用户名密码 •认证成功后显示欢迎信息 •输错三次后锁定 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 "" ...
- javascript中的时间处理
var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位,1970-???? ...
- 十一、常用的NSArray和NSMutableArray方法
1.概念 用来存储OBJ对象的有序列表,它是不可变的 2.创建常用方法 + (id)array + (id)arrayWithObect:(id)anObject + (id)arrayWithObe ...
- mybatis-config.xml详解
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...
- write_back 浅浅分析
hon@hon:~/f2fs$ grep -i "clearpagedirty" . -nr./mm/shmem.c:1240: ClearPageDirty(page);./mm ...
- GO To Definition的背后操作【VS2015 C#】
使用VS开发U3D项目时,去察看某个变量的声明,比如某组件的gameObject变量,会看到如下代码 一看似乎有点晕,这代码什么意思啊,就一个 public GameObject gameObject ...
- Tomcat6 一些调优设置内存和连接数
Tomcat6 一些调优设置内存和连接数 博客分类: java TomcatJVMLinux应用服务器网络应用 公司的一个服务器使用Tomcat6默认配置,在后台一阵全点击服务器就报废了,查了一下就 ...
- iOS 苹果自带地图定位Core Location
Core Location是iOS SDK中一个提供设备位置的框架.可以使用三种技术来获取位置:GPS.蜂窝或WiFi.在这些技术中,GPS最为精准,如果有GPS硬件,Core Location将优先 ...
- jdbc基础 (五) 连接池与数据源 DBCP以及C3P0的使用
一.连接池的概念和使用 在实际应用开发中,特别是在WEB应用系统中,如果JSP.Servlet或EJB使用JDBC直接访问数据库中的数据,每一次数据访问请求都必须经历建立数据库连接.打开数据库.存取数 ...