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 截取区间不能有半点差错.否则答案错误. 这两点 ...
随机推荐
- cmd返回上一级和根目录
https://jingyan.baidu.com/article/066074d6154cf4c3c21cb013.html
- Java 中的 List —— 有序序列
List 在 java 中是个有序序列: 一.容量 ArrayList 中有一个容量概念,表示基础数组的大小(无参时默认为 10).在需要的时候(比如 add操作)会自动增加其容量.LinkedLis ...
- ArcGIS AddIN开发之 设置当前工具为Edit Tool
在GIS数据处理中,经常需要选择要素,再进行操作.所以,为了处理的方便,可以将当前工具处理结束后,将当前工具设置为Edit Tool,以方便下一次的选择处理. 相关资料: 1.ArcMap Name ...
- 使用正则表达式进行某网页中的email邮箱抽取
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; impo ...
- 关于maven的CoreException: Could not get the value for parameter compilerId for plugin 。。的错误
在Eclipse中使用 Alt+F5 快捷键,在弹出的Update Maven Project对话框中选择报错的Maven工程,勾选下图中的 Force Update of Snapshots/Rel ...
- python全栈开发 * 18 面向对象知识点汇总 * 180530
18 面向对象初识1class person: level="高级动物" mind="有思想" def __init__(self,name,age,gent, ...
- Redis安装[Windows]
一. redis下载地址: https://github.com/ServiceStack/redis-windows/tree/master/downloads 根据需要的下载对应版本*.zip ...
- scala-协变和逆变
class GaoJi class ZhongJi extends GaoJi //协变=========================== class Card[+T] val cgaoji = ...
- TZOJ 3134: 渊子赛马修改版
描述 赛马是一古老的游戏,早在公元前四世纪的中国,处在诸侯割据的状态,历史上称为“战国时期”.在魏国作官的孙膑,因为受到同僚庞涓的迫害,被齐国使臣救出后,到达齐国国都. 赛马是当时最受齐国贵族欢迎的娱 ...
- vue 之组件递归;
在开发一个 PC 端的项目时,需要开发一个树状结构,直接上效果图如下:点击 "+" 号的时候则展开下一级,点击 "-" 号的时候则收起: 之所以写这篇博客,因为 ...