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 截取区间不能有半点差错.否则答案错误. 这两点 ...
 
随机推荐
- linux搭建mysql集群
			
一.公共配置 请在三个虚拟机上分别配置此处的配置项. 1. 安装虚拟机 虚拟机操作系统安装CentOS 6.5的x86_64版本. 2. 拷贝mysql cluster 下载以下版本的MySQL-Cl ...
 - php三级联动(html,php两个页面)
			
<!doctype html><html><head><meta charset="utf-8"><title>无标题文 ...
 - F#周报2019年第4期
			
新闻 F# 4.6预览 fuget.org现在显示包依赖从属,你曾经想要了解谁在使用你的类库吗?现在你可以知道了! F#被加入Wikipedia的流式接口页面 采访Erik Schierboom Az ...
 - nvm 淘宝镜像
			
找到里面的settings.txt node_mirror: https://npm.taobao.org/mirrors/node/npm_mirror: https://npm.taobao.or ...
 - RNN Train和Test Mismatch
			
李宏毅深度学习 https://www.bilibili.com/video/av9770302/?p=8 在看RNN的时候,你是不是也会觉得有些奇怪, Train的过程中, 是把训练集中的结果作为下 ...
 - 什么是Rollback Segment(已truncate和delete 命令为例)?
			
Rollback Segments是在你数据库中的一些存储空间,它用来临时的保存当数据库数据发生改变时的先前值,Rollback Segment主要有两个目的: 1. 如果因为某种原因或者其他用用户想 ...
 - [js]面向对象2
			
delete删除属性 删除对象的属性 删除未用var定义的变量. delete返回布尔 删除不存在的属性,返回true 无法删除原形中的属性 如 delete obj.toString() resu= ...
 - [js]js中4种无节操的预解释情况
			
js中4种无节操的预解释情况 - 1. if语句即使条件不成立,条件里的表达式也会进行预解释. - 2. 匿名函数的预解释: 只对等号左边与解释 - 3. 自执行函数的预解释: 不进行预就解释, 执行 ...
 - 【C】NO.85.EBook.10.C.1.001-【C primer plus】-
			
1.0.0 Summary Tittle:[C]NO.85.EBook.10.C.1.001-[C primer plus]- Style:C Series:C Since:2018-02-06 En ...
 - Docker:搭建私有镜像仓储(image registry)(4)
			
搭建私有仓储,其实本质上也是运行了一个官方提供的(Registry)镜像的容器:生产环境中,我们要搭建自己的专有仓储 下载registry镜像 docker pull registry 运行镜像 do ...