#1034 : 毁灭者问题

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

在 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
题解:
    自己写了一棵线段树的做法,看了网上一篇辣鸡博客,哎,无语了,
    自己写的时候是知道的这个写法比暴力还暴力,n^2logn的,但是还是
    写了,结果TLE,T飞了。
附上T飞代码
 #include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstdio> #define N 100007
#define ll long long
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if (ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,m;
ll ans;
struct Node
{
ll t,m,r,s;
}tr[N*]; inline void update(int p)
{
tr[p].s=tr[p<<].s+tr[p<<|].s;
}
void build(int p,int l,int r)
{
if (l==r)
{
tr[p].s=read(),tr[p].m=read(),tr[p].r=read();
tr[p].t=;
return;
}
int mid=(l+r)>>;
build(p<<,l,mid),build(p<<|,mid+,r);
update(p);
}
void renew(int p,int l,int r,int x,int y,int t)
{
if (l==r)
{
if (tr[p].s+(t-tr[p].t)*tr[p].r>tr[p].m) tr[p].s=tr[p].m;
else tr[p].s+=(t-tr[p].t)*tr[p].r;
tr[p].t=t;
return;
}
int mid=(l+r)>>;
if (y<=mid) renew(p<<,l,mid,x,y,t);
else if (x>mid) renew(p<<|,mid+,r,x,y,t);
else renew(p<<,l,mid,x,mid,t),renew(p<<|,mid+,r,mid+,y,t);
update(p);
}
ll query(int p,int l,int r,int x,int y)
{
if (l==x&&y==r) return tr[p].s;
int mid=(l+r)>>;
if (y<=mid) return query(p<<,l,mid,x,y);
else if (x>mid) return query(p<<|,mid+,r,x,y);
else return query(p<<,l,mid,x,mid)+query(p<<|,mid+,r,mid+,y);
}
void clean_all(int p,int l,int r,int x,int y)
{
if (l==r)
{
tr[p].s=;
return;
}
int mid=(l+r)>>;
if (y<=mid) return clean_all(p<<,l,mid,x,y);
else if (x>mid) return clean_all(p<<|,mid+,r,x,y);
else clean_all(p<<,l,mid,x,mid),clean_all(p<<|,mid+,r,mid+,y);
update(p);
}
int main()
{
freopen("fzy.in","r",stdin);
freopen("fzy.out","w",stdout); n=read(),build(,,n);
m=read();
for (int i=;i<=m;i++)
{
int t=read(),x=read(),y=read();
renew(,,n,x,y,t);
ans+=query(,,n,x,y);
clean_all(,,n,x,y);
}
printf("%lld",ans);
}

    正解思路

    对于s,m,r我们可以这样想,

    对于输入的间隔tk-tk-1,设为d,如果d*r>m 则为m 1

                   如果d*r<=m,则为r*d    2

    所以答案就等于所以人,满足1的个数乘以m,以及满足2的∑di  *r,这个就是答案。

    

    我们应该对于每个人来计算答案,对于每个人,如果暴力计算的话,就是O(nm)对吧。

    还是T飞,那怎么办呢,可以用一棵平衡树+线段树来维护,对于每个起始时间,结束时间

    都放入平衡树中,间隔即为判断条件,可以放入线段树中,结束时间时在维护,一下,删除

    所以,每个询问只会被插入一次,删除一次,对于每个人询问一次,所以总复杂度为O(nlgn)。

    代码,莫名wrong,但是对拍没有错,就精神ac吧。

 #include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<set>
#include<vector> #define lson tr[p].ls
#define rson tr[p].rs
#define z1 set<int>::iterator
#define N 100007
#define ll long long
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if (ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,m,root,sz;
ll ans;
vector<int>hd[N],ed[N];
set<int>q;//哪几个时间段有
struct Node
{
ll s,m,r;
}a[N];
struct Date
{
int num,sum,ls,rs;
}tr[]; inline void update(int p)
{
tr[p].sum=tr[lson].sum+tr[rson].sum;
tr[p].num=tr[lson].num+tr[rson].num;
}
void add(int &p,int l,int r,int x,int flag)
{
if(!p) p=++sz;
if (l==r)
{
tr[p].sum+=x*flag,tr[p].num+=flag;
return;
}
int mid=(l+r)>>;
if (x<=mid) add(lson,l,mid,x,flag);
else add(rson,mid+,r,x,flag);
update(p);
}
ll query1(int p,int l,int r,int x,int y)
{
if (!p) return ;
if (l==x&&r==y) return tr[p].sum;
int mid=(l+r)>>;
if (y<=mid) return query1(lson,l,mid,x,y);
else if (x>mid) return query1(rson,mid+,r,x,y);
else return query1(lson,l,mid,x,mid)+query1(rson,mid+,r,mid+,y);
}
ll query2(int p,int l,int r,int x,int y)
{
if (!p) return ;
if (l==x&&r==y) return tr[p].num;
int mid=(l+r)>>;
if (y<=mid) return query2(lson,l,mid,x,y);
else if (x>mid) return query2(rson,mid+,r,x,y);
else return query2(lson,l,mid,x,mid)+query2(rson,mid+,r,mid+,y);
}
int main()
{
freopen("fzy.in","r",stdin);
freopen("solution.out","w",stdout); n=read();
for (int i=;i<=n;i++)
a[i].s=read(),a[i].m=read(),a[i].r=read();
m=read();
for (int i=;i<=m;i++)
{
int t=read(),x=read(),y=read();
hd[x].push_back(t);
ed[y].push_back(t);
}
q.insert(-),q.insert(1e9+);//放一个哨兵。 for (int i=;i<=n;i++)
{
for (int j=;j<hd[i].size();j++)
{
z1 qq=q.lower_bound(hd[i][j]),hj=q.upper_bound(hd[i][j]);qq--;
if (*qq==-&&*hj==1e9+) q.insert(hd[i][j]);
else if (*qq==-)
{
q.insert(hd[i][j]);
add(root,,,*hj-hd[i][j],);
}
else if (*hj==1e9+)
{
q.insert(hd[i][j]);
add(root,,,hd[i][j]-*qq,);
//cout<<hd[i][j]-*qq<<" flag"<<endl;
}
else
{
add(root,,,*hj-*qq,-);
q.insert(hd[i][j]);
add(root,,,hd[i][j]-*qq,),add(root,,,*hj-hd[i][j],);
}
}
int up=ceil(a[i].m*1.0/(double)a[i].r);
ans+=query1(root,,,,up-)*a[i].r;
ans+=query2(root,,,up,)*a[i].m;
z1 t=q.begin();t++;
if (*t!=)
{
if (*t*a[i].r+a[i].s>a[i].m) ans+=a[i].m;
else ans+=*t*a[i].r+a[i].s;
}
for (int j=;j<ed[i].size();j++)
{
z1 qq=q.lower_bound(ed[i][j]),hj=q.upper_bound(ed[i][j]);qq--;
if (*qq==-&&*hj==1e9+) q.erase(ed[i][j]);
else if (*qq==-)
{
q.erase(ed[i][j]);
add(root,,,*hj-ed[i][j],-);
}
else if (*hj==1e9+)
{
q.erase(ed[i][j]);
add(root,,,ed[i][j]-*qq,-);
}
else
{
add(root,,,ed[i][j]-*qq,-),add(root,,,*hj-ed[i][j],-);
q.erase(ed[i][j]);
add(root,,,*hj-*qq,);
}
}
// cout<<ans<<endl;
}
printf("%lld",ans);
}

hihocoder #1034 : 毁灭者问题 平衡树(set)+线段树的更多相关文章

  1. 【学习笔记】浅析平衡树套线段树 & 带插入区间K小值

    常见的树套树 一般来说,在嵌套数据结构中,线段树多被作为外层结构使用. 但线段树毕竟是 静态 的结构,导致了一些不便. 下面是一个难以维护的例子: 带插入区间 \(k\) 小值问题 来源:Luogu ...

  2. hihocoder #1034 毁灭者问题

    传送门 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在 Warcraft III 之冰封王座中,毁灭者是不死族打三本后期时的一个魔法飞行单位. 毁灭者的核心技能之一, ...

  3. bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1807  Solved: 772[Submit][Stat ...

  4. BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)

    我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...

  5. bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description ...

  6. [bzoj3065] 带插入区间第k小值 [重量平衡树套线段树]

    题面 传送门 思路 发现强制在线了...... 本来可以树套树解决的问题,现在外层不能使用线段树了,拿什么替代呢? 我们需要一种支持单点插入.下套数据结构.数据结构上传合并复杂度最多单log,不能旋转 ...

  7. BZOJ3196 二逼平衡树 【线段树套平衡树】

    题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ...

  8. CEOI 2019 Day2 T2 魔法树 Magic Tree (LOJ#3166、CF1993B、and JOI2021 3.20 T3) (启发式合并平衡树,线段树合并)

    前言 已经是第三次遇到原题. 第一次是在 J O I 2021 S p r i n g C a m p \rm JOI2021~Spring~Camp JOI2021 Spring Camp 里遇到的 ...

  9. [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

    题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...

随机推荐

  1. Linux环境下MySQL5.7安装记录

    参考文档 <Installing MySQL on Unix/Linux Using Generic Binaries> https://dev.mysql.com/doc/refman/ ...

  2. 为HttpClient和HttpURLConnection添加中国移动代理

    转自: http://www.2cto.com/kf/201111/112100.html 在android中,一般需要联网的时候前,都要做一次网络的判断,判断当前的网络状态!然后开始请求网络 当我们 ...

  3. 移动端如何定义字体font-family

    移动端如何定义字体font-family 中文字体使用系统默认即可,英文用Helvetica /* 移动端定义字体的代码 */ body{font-family:Helvetica;} 参考<移 ...

  4. DEV—【GridControl 按钮列无法触发点击事件解决方案】

    需要在按钮列的OptionColumn属性栏中找到下面两个属性,并且改为True AllowEdit=True,AllowFocus=True.

  5. IIS 的最大并发数

    为了探寻IIS的最大并发数,先要做几个假设. 1.假设最大并发数就是当前的连接数.意思是当前能承受最大的连接,那么就表明最大的并发.2.假设IIS应用程序池处于默认状态,更改设置将会对最大连接数产生影 ...

  6. 关于.Net中Process的使用方法和各种用途汇总(二):用Process启动cmd.exe完成将cs编译成dll

    上一章博客我为大家介绍了Process类的所有基本使用方法,这一章博客我来为大家做一个小扩展,来熟悉一下Process类的实际使用,废话不多说我们开始演示. 先看看我们的软件要设计成的布局吧. 首先我 ...

  7. [ BZOJ 2038 ] Hose

    \(\\\) Description 给出一个数列,多次询问,每次给出一个区间 \([l_i,r_i]\) ,问在区间中随意选两个位置不同的数,是同一个数的概率有多大. \(n,m\le 5\time ...

  8. Angular广播/消息通知的接收与发送

    一.在接收页:添加引用: private eventManager: JhiEventManager: 接收通知的方法: // 接收通知(新建.编辑.删除页发送过来的通知) // upmsMenuLi ...

  9. CSS综合用法

    div 居中 {position: absolute; top: 50%; left: 50%; margin-top: -180px; margin-left: -160px;}

  10. JS中的对象之原型

    对象 ECMAScript做为一个高度抽象的面向对象语言,是通过_对象_来交互的.即使ECMAScript里边也有_基本类型_,但是,当需要的时候,它们也会被转换成对象. 一个对象就是一个属性集合,并 ...