FJUT3701 这也是一道数论题(线段树)题解
Problem Description
好久没出数据结构题,现在赶紧来做道数据结构题热热身
小q现在要去银行,他有个很厉害的bug能看到前面排队的人。假如当前有人正在办理业务,那么肯定要等待前一个人完成。现在有m个事件,分为3种。第一种是第x时刻有客人到银行办理业务,用时t。第二种是第i个事件中的客人取消去银行。第三种是小q想询问他第x分钟去银行需要等多久。小q是个礼貌的人如果有人跟他同一时刻到达,他会让别人先。
Input
单组数就
第一行输入一个整数m,代表m个事件。
接下来m行输入3种操作之一。
+ x t代表第x时刻有客人到银行办理业务,用时t(1<=x,t<=10^6)
- i 代表第i个事件中的客人取消业务办理(1<=i<=m)
?x代表小q想知道如果他在时刻x去,要等多久(1<=x<=10^6)
30%数据:m<=1000
100%数据 m<=300000
Output
对于每个?事件输出一行,只包含一个整数,代表答案
SampleInput
19
? 3
+ 2 2
? 3
? 4
+ 5 2
? 5
? 6
+ 1 2
? 2
? 3
? 4
? 5
? 6
? 7
? 9
- 8
? 2
? 3
? 6
SampleOutput
0
1
0
2
1
3
2
1
2
1
0
0
2
1
1
样例解释:如果小q第3时刻来,前面没有人所以等待0.如果第3时刻来,前面有个客人为(2,2)第4时刻才结束,那么小q则需要等待1...
思路:
假设从j时刻开始,后面到的所有人都要开始排队,我们假设每个时刻总用时a[j](也就是题目中的t)
a[j]前缀和设为sum[j]
所以i时刻的排队时间为 sum[i] - sum[j] - (i - (j + 1))
那么怎么快速找到这个j呢?显然如果sum[i] - sum[j] < (i - (j + 1)),那就是不用排队,我们取0;如果sum[i] - sum[j] > (i - (j + 1)),那我们就找出 max(sum[i] - sum[j] - (i - (j + 1)))
综上,结果应是max(sum[i] - sum[j] - (i - (j + 1)),0) 1<=j<i,由于i确定,所以可以转化为 sum[i] - i + 1 + max(j - sum[j]),用线段树维护j - sum[j]的最大值和sum[i]
代码:
#include<cmath>
#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e6 + ;
const ull seed = ;
const int INF = 0x3f3f3f3f;
const int MOD = ;
ll sum[maxn << ], Max[maxn << ], lazy[maxn << ];
int t[maxn], p[maxn], v[maxn];
void pushDown(int rt){
if(lazy[rt]){
lazy[rt << ] += lazy[rt];
lazy[rt << | ] += lazy[rt];
sum[rt << ] += lazy[rt];
sum[rt << | ] += lazy[rt];
Max[rt << ] -= lazy[rt];
Max[rt << | ] -= lazy[rt];
lazy[rt] = ;
}
}
void build(int l, int r, int rt){
if(l == r){
Max[rt] = l;
return;
}
int m = (l + r) >> ;
build(l, m, rt << );
build(m + , r, rt << | );
Max[rt] = max(Max[rt << ], Max[rt << | ]);
}
void update(int L, int R, int l, int r, int rt, ll v){
if(L <= l && R >= r){
lazy[rt] += v;
sum[rt] += v;
Max[rt] -= v;
return;
}
pushDown(rt);
int m = (l + r) >> ;
if(L <= m)
update(L, R, l, m, rt << , v);
if(R > m)
update(L, R, m + , r, rt << | , v);
Max[rt] = max(Max[rt << ], Max[rt << | ]);
}
ll queryMax(int L, int R, int l, int r, int rt){
if(R <= ) return ;
if(L <= l && R >= r){
return Max[rt];
}
pushDown(rt);
int m = (l + r) >> ;
ll MAX = -INF;
if(L <= m)
MAX = max(MAX, queryMax(L, R, l, m, rt << ));
if(R > m)
MAX = max(MAX, queryMax(L, R, m + , r, rt << | ));
Max[rt] = max(Max[rt << ], Max[rt << | ]);
return MAX;
}
ll querySum(int pos, int l, int r, int rt){
if(pos == ) return ;
if(l == r){
return sum[rt];
}
pushDown(rt);
int m = (l + r) >> ;
ll ans;
if(pos <= m)
ans = querySum(pos, l, m, rt << );
else
ans = querySum(pos, m + , r, rt << | );
Max[rt] = max(Max[rt << ], Max[rt << | ]);
return ans;
}
int main(){
int n, m;
int e = ;
build(, e, );
scanf("%d", &m);
for(int i = ; i <= m; i++){
char o[];
int x, tt;
scanf("%s", o);
if(o[] == '+'){
scanf("%d%d", &p[i], &v[i]);
update(p[i], e, , e, , v[i]);
}
else if(o[] == '-'){
scanf("%d", &x);
update(p[x], e, , e, , -v[x]);
}
else{
scanf("%d", &x);
ll SumI = querySum(x, , e, );
ll MaxJ = max(queryMax(, x - , ,e, ), 0LL);
printf("%lld\n", SumI - x + + MaxJ);
//sum[i] - sum[j] - (i - (j + 1))
//sum[i] - i + 1 + (j - sum[j])
}
}
return ;
}
/*
假设从j位置开始,后面所有人都要开始排队,每个位置用时a[j]
a[j]前缀和sum[j]
所以i位置排队 = sum[i] - sum[j] - (i - (j + 1))
*/
FJUT3701 这也是一道数论题(线段树)题解的更多相关文章
- FJUT-这还是一道数论题
这还是一道数论题 TimeLimit:4000MS MemoryLimit:128MB 64-bit integer IO format:%lld Special Judge Problem D ...
- [BJOI2019]删数(线段树)
[BJOI2019]删数(线段树) 题面 洛谷 题解 按照值域我们把每个数的出现次数画成一根根的柱子,然后把柱子向左推导,\([1,n]\)中未被覆盖的区间长度就是答案. 于是问题变成了单点修改值,即 ...
- P3939 数颜色 线段树动态开点
P3939 数颜色 线段树动态开点 luogu P3939 水.直接对每种颜色开个权值线段树即可,注意动态开点. #include <cstdio> #include <algori ...
- poj 3468 A Simple Problem with Integers(原来是一道简单的线段树区间修改用来练练splay)
题目链接:http://poj.org/problem?id=3468 题解:splay功能比线段树强大当然代价就是有些操作比线段树慢,这题用splay实现的比线段树慢上一倍.线段树用lazy标记差不 ...
- BZOJ2120&2453数颜色——线段树套平衡树(treap)+set/带修改莫队
题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2 ...
- BZOJ 3813--奇数国(线段树&欧拉函数&乘法逆元&状态压缩)
3813: 奇数国 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 755 Solved: 432[Submit][Status][Discuss] ...
- Luogu5324 BJOI2019删数(线段树)
考虑无修改怎么做.对于1~n的每个数,若其存在,将最后一个放在其值的位置,剩余在其前面依次排列,答案即为值域1~n上没有数的位置个数.带修改显然记一下偏移量线段树改一改就好了. #include< ...
- POJ1389:Area of Simple Polygons——扫描线线段树题解+全套代码注释
http://poj.org/problem?id=1389 题面描述在二维xy平面中有N,1 <= N <= 1,000个矩形.矩形的四边是水平或垂直线段.矩形由左下角和右上角的点定义. ...
- HDU 1556 Color the Ball 线段树 题解
本题使用线段树自然能够,由于区间的问题. 这里比較难想的就是: 1 最后更新须要查询全部叶子节点的值,故此须要使用O(nlgn)时间效率更新全部点. 2 截取区间不能有半点差错.否则答案错误. 这两点 ...
随机推荐
- 将 Entity Framework、LINQ 和 Model-First 用于 Oracle 数据库
目的 本教程介绍如何使用 Entity Framework.语言集成查询 (LINQ),以及如何对 Oracle 数据库使用 Model-First 以生成数据定义语言 (DDL) 脚本. 所需时间 ...
- laravel+阿里大于实现发送验证码短信
一.短信服务使用阿里大于提供的短信接口 阿里大于官方网站上的接入流程: 在阿里大于申请接口后,需要做以下操作: 申请签名 申请短信模板 创建Accesskey,可以通过权限最大的Accesskey创建 ...
- php 获取IP地址 并获取坐标lat lng 并获取到所在地区
函数方法:ps:只能放在服务器上起效果,放在本地是无法起效果的 /* **根据ip获取坐标 ***/ function get_zuobiao(){ $user_IP = ($_SERVER[&quo ...
- vue2.0 vs vue
vue2.0相比vue1.0 有哪些改变,今天总结了一下 vue2.0组件中 template 不在支持代码片段 //vue1.0组件中template写法 <template> < ...
- spfa最短路径
C++代码 #include <iostream> #include <deque> #include <stack> #include <vector> ...
- 存储开头结尾使用begin tran,rollback tran作用?
BEGIN TRAN你就把它看成一个还原点,一般用在INSERT.UPDATE.DELETE等能改变数据操作前设置,如果操作后发现执行的结果和预期的不一样,就ROLLBACK,反之就COMMIT提交
- vim快捷键与vi
vim与程序员 所有的 Unix Like 系统都会内建 vi 文书编辑器,其他的文书编辑器则不一定会存在. 但是目前我们使用比较多的是 vim 编辑器. vim 具有程序编辑的能力,可以主动的以字体 ...
- python基础,if语句,while循环
if语句: ①2选一 ④多选一 if: 条件 ...
- shiro 角色与权限的解读
1.为什么 shiro 有了<角色>后,还要设置<角色权限>呢?(问题) 思考:设置好角色了,那么就代表什么操作都可以执行了吗? 理解:如果上边回答是的话,那么只是<角色 ...
- js map()与forEach()的用法与区别
forEach 和map 都是用来遍历数组,二者的区别为: forEach() 会修改原来的数组,而map() 方法会得到一个新的数组并返回,不会修改原来的数组 二者的执行速度方面,经过jsPerf( ...