【BZOJ4843】[Neerc2016]Expect to Wait 排序

【BZOJ4843】[Neerc2016]Expect to Wait

Description

ls最近开了一家图书馆,大家听说是ls开的,纷纷过来借书,自然就会出现供不应求的情况, 并且借书的过程类似一个队列,每次有人来借书就将它加至队尾,每次有人来还书就把书借给队头的若干个人,定义每个人的等待时间为拿到书的时刻减去加至队列的时刻,如果一个人根本就拿不到书,则等待时间为inf,现在给出所有时刻借书还书的情况,和若干个询问,每次询问当图书馆初始有x本书时所有人的等待时间之和是多少(如果存在一个人根本拿不到书,则输出INFINITY)。

Input

第一行两个整数n,q(1<=n,q<=100000),表示有n个时刻有借书还书的情况,以及有q个询问。
接下来n行,每行表示一个操作,操作如下:
1."+ t k" 在t时刻有k本书被还回来。
2."- t k" 在t时刻有k个人来借书。
(1<=t<=1e9,1<=k<=10000)
输入顺序保证t递增。
接下来一行q个数,第i个数bi(1<=bi<=1e9)表示图书馆初始有bi本书,询问所有人的等待时间之和为多少。

Output

一共q行,每行一个数表示等待时间之和,如果存在一个人根本拿不到书,则输出INFINITY。

Sample Input

5 4
- 1 1
- 2 2
+ 4 1
- 6 1
+ 7 2
0 3 1 2

Sample Output

INFINITY
0
8
3

题解:将借书看成+x,换书看成-x,然后在时间轴上求前缀和,发现那些权值>0的线段的加权长度即时总等待时间。那么如果初始有y本书呢?则我们只需要计算所有权值>y的线段的加权长度。将所有线段排个序即可。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=100010;
int n,m,tot;
ll sum,sv,sl;
char str[10];
ll ans[maxn],t[maxn];
struct node
{
	ll val,len;
}p[maxn];
struct query
{
	int org;
	ll val;
}q[maxn];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
bool cmp1(node a,node b)
{
	return a.val>b.val;
}
bool cmp2(query a,query b)
{
	return a.val>b.val;
}
int main()
{
	n=rd(),m=rd();
	int i,j,a;
	for(i=1;i<=n;i++)
	{
		scanf("%s",str),t[i]=rd(),a=rd();
		if(sum>0)	p[++tot].val=sum,p[tot].len=t[i]-t[i-1];
		if(str[0]=='+')	a=-a;
		sum+=a;
	}
	for(i=1;i<=m;i++)	q[i].val=rd(),q[i].org=i;
	sort(p+1,p+tot+1,cmp1);
	sort(q+1,q+m+1,cmp2);
	for(i=j=1;i<=m;i++)
	{
		for(;p[j].val>q[i].val&&j<=tot;j++)	sv+=p[j].val*p[j].len,sl+=p[j].len;
		if(q[i].val<sum)	ans[q[i].org]=-1;
		else	ans[q[i].org]=sv-sl*q[i].val;
	}
	for(i=1;i<=m;i++)
	{
		if(ans[i]==-1)	printf("INFINITY\n");
		else	printf("%lld\n",ans[i]);
	}
	return 0;
}
posted @ 2017-08-26 09:26  CQzhangyu  阅读(399)  评论(0编辑  收藏  举报