这道题卡了我好久,一开始的思路可能有点问题,导致后面越来越乱....
一开始我是这样想的,对于每个人,他的等待时间是他拿到书的时间减去他借书的时间,那么总等待时间就是所有人拿到书的时间减去所有人借书的时间,我们维护书的数目,然后发现对于一次还书,它的贡献是有些人在此刻拿到书,对于一次借书,它的贡献就是有些人在此刻借书,然后离线搞一搞...后来发现这种写法细节颇多,然后就弃疗了.
后来的思想是我们把等待时间看成一段一段的,对于每个前缀和为负的位置,说明有这么多个人还没拿到书,那么这么多个人就一定要等这一段时间,这样的话我们就离线排个序,然后维护前缀和的正负和答案的变化量,这样就比较好搞了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define maxn 100005 6 typedef long long LL; 7 LL ans[maxn],cur,sumt; 8 int n,q; 9 pair<int,int> A[maxn],B[maxn]; 10 11 inline int read(void) 12 { 13 int x=0; 14 char ch=getchar(); 15 while (ch>'9'||ch<'0') ch=getchar(); 16 while (ch<='9'&&ch>='0') 17 { 18 x=x*10+ch-'0'; 19 ch=getchar(); 20 } 21 return x; 22 } 23 24 void init(void) 25 { 26 for (int i=1;i<=n;i++) A[i].first+=A[i-1].first; 27 for (int i=1;i<n;i++) A[i].second=A[i+1].second-A[i].second; 28 sort(B+1,B+q+1); 29 int pp=1,p=n; 30 while (B[pp].first+A[n].first<0&&pp<=q) ans[B[pp].second]=-1,pp++; 31 sort(A+1,A+n+1); 32 while (A[p].first+B[pp].first>=0&&p>=1) p--; 33 for (int i=1;i<=p;i++) 34 { 35 sumt+=A[i].second; 36 cur-=(LL)A[i].second*(A[i].first+B[pp].first); 37 } 38 ans[B[pp].second]=cur; 39 for (int i=pp+1;i<=q;i++) 40 { 41 while (B[i].first+A[p].first>=0&&p>=1) 42 { 43 sumt-=A[p].second; 44 cur+=(LL)(B[i-1].first+A[p].first)*A[p].second; 45 p--; 46 } 47 cur-=sumt*(B[i].first-B[i-1].first); 48 ans[B[i].second]=cur; 49 } 50 } 51 52 int main() 53 { 54 n=read();q=read(); 55 for (int i=1;i<=n;i++) 56 { 57 char s[3]; 58 scanf("%s",s); 59 A[i].second=read(); 60 A[i].first=read(); 61 if (s[0]=='-') A[i].first=-A[i].first; 62 } 63 for (int i=1;i<=q;i++) B[i].first=read(),B[i].second=i; 64 init(); 65 for (int i=1;i<=q;i++) 66 if (ans[i]==-1) puts("INFINITY"); 67 else printf("%lld\n",ans[i]); 68 return 0; 69 }