题目背景
zeromaker 是个手残,但是他喜欢玩东方 project,ex 什么的最喜欢了
题目描述
zeromaker 对弹幕的视野控制有着深刻的研究。 每个弹幕在一段特定的时间内会出现在 zeromaker 的视野内,除此之外的时间都在 zeromaker 看不到的地方。在 zeromaker 看来,视野内的弹幕数量越多,图就越难,因为这意味着 @#¥%。 现在,zeromaker 想要评测这张图的难度,他已经知道了每个弹幕会在什么时候出现在视野内,他想知道,在一段时间内,总共有多少个弹幕出现在他的视野内过。
输入格式
第一行有两个整数 n , m ,表示一共有 n 个弹幕,而 zeromaker 有 m 个问题。
接下来 n 行,每行两个数 a,b,表示这个弹幕a 秒时出现在 zeromaker 的视野内,出现了 b 秒。 接下来 m 行,每行两个整数 x , y ,表示从 x 秒开始,经过 y秒,其中有多少个弹幕出现过。
注意:查询区间为左闭右闭,弹幕出现区间为左开右开。
输出格式
m 行,即对于 zeromaker 提出的每个问题的答案。
输入输出样例
输入 #1 输出#1
3 2 3 2 5 2 0 10 5 8 0 6 8 2
输入#2 输出#2
1 2 1 0 10 0 9 1 10 1
解题思路:
分两块来看:1.弹幕出现区间 2.查询区间
1.弹幕出现区间:
由题意,弹幕出现区间为开区间,若a秒出现在视野中,出现了b秒,则能看到弹幕的第一秒为a,最后一秒为a+b-1
如图,假设从左进入视野,向右滚动,第a+b秒为:
所以,可以设定两个数组 l、r,数组l储存所有弹幕出现的时间(即出现在左端的时间),数组r储存所有弹幕出现的最后一秒(即出现在右端的时间)
再用sort函数将两个数组分别排序,可以得到依次、分别得到出现在左端和右端的时间。
2.查询区间
由题意,查询区间为闭区间,所以无需减一,查询弹幕的第一秒为a,最后一秒为a+b
确定弹幕出现区间和查询区间后,可以用两次lower_bound函数得到结果
设定查询的第一秒为l2,持续r2秒,即查询最后一秒为l2+r2
首先在数组l中 用lower_bound(l,l+n,r2)-l 即在l数组中返回大于等于r2的第一个值的位置①
随后在数组r中 用lower_bound(r,r+n,l2)-r 即在r数组中返回大于等于l2的第一个值的位置②
最后由①-②,便能得到在该段时间内总共出现的弹幕数量。
代码:
#include <iostream> #include <algorithm> using namespace std; int main() { int n,m,i,l[100001],r[100001];//l[i]出现,r[i]最后出现的时间 cin>>n>>m; for(i=0;i<n;i++) { cin>>l[i]>>r[i]; r[i]=l[i]+r[i]-1;//开区间,减一 } sort(l,l+n); sort(r,r+n);//分别进行排序,所有的出现时间和最后时间按顺序 for(i=0;i<m;i++) { int l2,r2,s; cin>>l2>>r2; r2=l2+r2;//闭区间,不用减一 s=lower_bound(l,l+n,r2)-l;//在所有弹幕出现时间里返回大于等于r2的一个值的位置 s-=lower_bound(r,r+n,l2)-r;//上面的数减去 弹幕最后出现的时间里大于等于l2的第一个值的位置 cout<<s<<endl; } return 0; }