2016-2017 ACM-ICPC Northeastern European Regional Contest (NEERC 16) Gym - 101190E 询问离线,排序

题目链接:http://codeforces.com/gym/101190/attachments

题意:一个公共三轮车车站可以提供给一些人租车,但是在开始时刻,公园里有所少量车这个是不确定的,然后现在有n个信息和q个询问,信息有两种形式+ a b代表在a时间有b个人还车,另外一种是 - a b代表在a时间有b个人借车,这些人借车是要排队的,如果当前没有车,则只能等待,对于每一个询问给定了初始时刻车站里面有多少量车,然后要询问的是对于每一个可能的初始值的等待时间,如果等待时间是不确定的话,输出INFINITY。

解法:首先是一个单点更新的问题,可是我们发现一次更新之后会影响下一次的查询,或者你更新之后又可以回到之前的版本,所以可持久化?瞎几把yy之后,我们不妨来分析一下样例,可以观察到什么时候是要租车的呢?首先输入的信息用 op t[i] a[i]来表示一下,t[i]代表时间戳,a[i]代表人或者车的数量(取决于操作),第二种操作意味着要减少a[i]量车,如果车你的数量减小到<=0那么久只能等待了。并且当前要等待的时间是多少呢?我们容易把它预处理出来,下面的s[i]就是人或者车的数量的前缀和,显然为正代表当前时间不需要租车,否则需要租车。

    for(int i = 1; i <= n; i++){
        s[i] = s[i-1] + a[i];
        if(i < n) t[i] = t[i+1] - t[i];
    }

处理出这个也不能解决这个问题,接下来显然当s[i]>0的那些时间段是不用考虑的,你想啊,当前车的数量够用,肯定傻子才会等待吧。所以我们把需要等待的总时间以及等待的时间段的长度记录下来

long long sum1 = 0, sum2 = 0;
    for(int i = 1; i <= n; i++){
        if(s[i] < 0){
            b[++cnt] = i;
            sum1 += 1LL*(-s[i])*t[i];
            sum2 += t[i];
        }
    }

接下来就是想到我们在线很难做那么我们可以离线做啊,所以就有了询问离线的思路了。我们会想离线该怎么做呢?容易想到我们会按照x来排序,离线是为了能用到之前处理的信息,而不是无序重来一遍,这样显然是可以降低复杂度的吧。所以我们会想到按照x从小到大排序,这里的x就是第初始的车的数量,想一下吧,当前x比较小的时候你覆盖了一些之前等待的时间区间,那么下次你的x比现在的大,也必然可以覆盖上次的区间,所以就不用重复扫描,自然大大降低了复杂度。

struct node{
    int x, id;
    bool operator < (const node &rhs) const{
        return x < rhs.x;
    }
}c[maxn];

在询问离线的时候我已经提到了,要利用之前的信息,所以我们也要对那些需要等待的时间段进行排序,每一个时间段都有一个值代表当前等待的人数,这里是负数所以从大到小排,比如-2>-3,那么2会排在3的前面,那么你x增大,显然也是可以覆盖当前区间能覆盖的每一条线段的,然后我们按照这个思路去模拟一发就可以了。注意不确定的条件就是当当前的x+s[n]<0的时候,这个时候显然车都不够。

    sort(c + 1, c + q + 1);
    for(int i = 1; i <= q; i++){
        int x = c[i].x;
        while(j <= cnt && (-s[b[j]]) <= x){
            sum1 -= 1LL*(-s[b[j]]) * t[b[j]];
            sum2 -= t[b[j]];
            ++j;
        }
        if(s[n] + x < 0){
            ans[c[i].id] = -1;
        }
        else{
            ans[c[i].id] = sum1 - x * sum2;
        }
    }

完整码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
int n, q;
int a[maxn], t[maxn];
int s[maxn];
int b[maxn], cnt;
long long ans[maxn];
struct node{
    int x, id;
    bool operator < (const node &rhs) const{
        return x < rhs.x;
    }
}c[maxn];
bool cmp(int i, int j){
    return s[i] > s[j];
}

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 op[5];
        scanf("%s%d%d", op, &t[i], &a[i]);
        if(op[0] == '-') a[i] = -a[i];
    }
    //处理出初始的信息
    for(int i = 1; i <= n; i++){
        s[i] = s[i-1] + a[i];
        if(i < n) t[i] = t[i+1] - t[i];
    }
//    for(int i = 1; i <= n; i++){
//        printf("s[%d] = %d, t[%d] = %d\n", i, s[i], i, t[i]);
//    }
    long long sum1 = 0, sum2 = 0;
    for(int i = 1; i <= n; i++){
        if(s[i] < 0){
            b[++cnt] = i;
            sum1 += 1LL*(-s[i])*t[i];
            sum2 += t[i];
        }
    }
    sort(b + 1, b + cnt + 1, cmp);
    int j = 1;
    long long k = 0;
    for(int i = 1; i <= q; i++){
        scanf("%d", &c[i].x);
        c[i].id = i;
    }
    sort(c + 1, c + q + 1);
    for(int i = 1; i <= q; i++){
        int x = c[i].x;
        while(j <= cnt && (-s[b[j]]) <= x){
            sum1 -= 1LL*(-s[b[j]]) * t[b[j]];
            sum2 -= t[b[j]];
            ++j;
        }
        if(s[n] + x < 0){
            ans[c[i].id] = -1;
        }
        else{
            ans[c[i].id] = sum1 - x * sum2;
        }
    }
    for(int i = 1; i <= q; i++){
        if(ans[i] == -1) printf("INFINITY\n");
        else printf("%lld\n", ans[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值