【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
- 1 1
- 2 2
+ 4 1
- 6 1
+ 7 2
0 3 1 2
Sample Output
INFINITY
0
8
3
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 "); else printf("%lld ",ans[i]); } return 0; }