Gym - 101190E

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

可以得到总等待时间为

\sum_{i=1}^{n-1} max\{-a_i+x,0\} \cdot (t_{i+1}-t_i)

这样,我们就可以离线查询最终的结果

#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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值