https://vjudge.net/problem/Gym-101190E
题意:你知道在每个时刻需要用车和还车的人数,问当初始有bi辆车的时候,所有人的等待时间(时刻数小于1e5,询问数小于1e5)
我们考虑转化一下计算方式,假设初始没车,先列出每个时刻剩余车的数量
对于样例:
5 4
- 1 1
- 2 2
+ 4 1
- 6 1
+ 7 2
0 3 1 2
我们得到每个时刻车的数量:
t a
0 0
1 -1
2 -3
4 -2
6 -3
7 -1
对于任意询问x
可以得到总等待时间为
这样,我们就可以离线查询最终的结果
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n,q;
map<int,int> m;
map<int,ll> ans;
vector<pair<int,int> > a;
vector<pair<int,int> > v;
int b[100005];
int c[100005];
int main()
{
freopen("expect.in","r",stdin);
freopen("expect.out","w",stdout);
scanf("%d%d",&n,&q);
for (int i=1;i<=n;i++)
{
char s[5];
int x,y;
scanf("%s%d%d",s,&x,&y);
if (s[0]=='+') m[x]=m[x]+y;
else m[x]=m[x]-y;
}
a.push_back({0,0});
for (auto x:m)
{
a.push_back({x.first,a[a.size()-1].second+x.second});
}
for (int i=1;i<=q;i++)
{
scanf("%d",&b[i]);
c[i]=b[i];
}
sort(c+1,c+q+1);
for (int i=0;i<(int)a.size()-1;i++)
{
if (a[i].second<0)
{
v.push_back({-a[i].second,a[i+1].first-a[i].first});
}
}
sort(v.begin(),v.end());
reverse(v.begin(),v.end());
int f=1;
for (int i=1;i<=q;i++)
{
if (c[i]+a[a.size()-1].second<0)
{
ans[c[i]]=-1;
f=i+1;
}
else break;
}
ll an=0;
while (!v.empty() && v.back().first-c[f]<=0)
{
v.pop_back();
}
ll sum=0;
for (auto x:v)
{
sum+=x.second;
an+=(ll)(x.first-c[f])*x.second;
}
if (f<=q) ans[c[f]]=an;
for (int i=f+1;i<=q;i++)
{
while (!v.empty() && v.back().first-c[i]<=0)
{
sum-=v.back().second;
an-=(ll)(v.back().first-c[i-1])*v.back().second;
v.pop_back();
}
an-=sum*(c[i]-c[i-1]);
ans[c[i]]=an;
}
for (int i=1;i<=q;i++)
{
ll x=ans[b[i]];
if (x==-1) printf("INFINITY\n");
else printf("%I64d\n",x);
}
return 0;
}