借教室(差分数组+二分)

1711: 借教室

时间限制: 1 Sec  内存限制: 128 MB
提交: 179  解决: 24
[提交][状态][讨论版][命题人:admin]

题目描述

在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。
面对海量租借教室的信息,我们自然希望编程解决这个问题。
我们需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借。共有m份订单,每份订单用三个正整数描述,分别为dj, sj, tj ,表示某租借者需要从第sj 天到第tj 天租借教室(包括第sj天和第tj天),每天需要租借dj个教室。
我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。
借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第sj天到第tj天中有至少一天剩余的教室数量不足dj个。
现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。

输入

第一行包含两个正整数n, m,表示天数和订单的数量。
第二行包含n个正整数,其中第i个数为ri,表示第i天可用于租借的教室数量。
接下来有m行,每行包含三个正整数dj, sj, tj ,表示租借的数量,租借开始、结束分别在第几天。

每行相邻的两个数之间均用一个空格隔开。天数与订单均用从1开始的整数编号。

输出

如果所有订单均可满足,则输出只有一行,包含一个整数 0。否则(订单无法完全满足)输出两行,第一行输出一个负整数-1,第二行输出需要修改订单的申请人编号。

 

 

样例输入

4 3

2 5 4 3

2 1 3

3 2 4

4 2 4

 

样例输出

-1

2

提示

第1份订单满足后,4天剩余的教室数分别为0,3,2,3。第2份订单要求第2天到第4天每天提供3个教室,而第3天剩余的教室数为2,因此无法满足。分配停止,通知第2个申请人修改订单。

对于100%的数据,有1≤n,m≤10^6,0≤ri,dj≤10^9,1≤sj≤tj≤n。

 

一道可以用线段树的题,不过线段树还只是入门,不太会写,就用差分数组和二分写了这道题(不过差分也是现学的。。)

差分略有变动,不过原理还是原来的没变

先全部计算,若不满足,再进行二分求第几个不满足

#include 
using namespace std;
const int INF = 1e6 + 10;
int a[INF], d[INF], r[INF];
int n, m;
struct node
{
    int x,s,e;
}b[INF];
int judge(int ss, int ee) {
    memset(d,0,sizeof(d));
    for (int i = ss; i <= ee; i++) {
        d[b[i].s] += b[i].x;
        d[b[i].e + 1] -= b[i].x;
    }
    //r[0] = 0;
    for (int i = 1; i <= n; i++) {
        r[i] = r[i - 1] + d[i];
        if (r[i] > a[i]) return 0;
    }
    return 1;
}
int main() {
    scanf("%d%d",&n,&m);
    a[0] = 0;
    for (int i = 1; i <= n; i++) {
        scanf("%d",&a[i]);
        d[i] = a[i] - a[i - 1];
    }
    for (int i = 1; i <= m; i++) {
        scanf("%d%d%d",&b[i].x,&b[i].s,&b[i].e);
    }
    if (judge(1, m)) {
        printf("0\n");
        return 0;
    }
    int beginn = 1, endd = m, mid;
    while (beginn < endd) {
        mid = (beginn + endd) / 2;
        if (judge(1, mid) ) beginn = mid + 1;
        else    endd = mid;
    }
    printf("-1\n");
    printf("%d\n",endd);
    return 0;
}

简单总结一下查分数组

当数组[l,r]区间内的值都需要更新时,一个一个更新显然很耗费时间,所以差分数组可以再a[l],a[r+1]处进行修改

如要加一,则a[l]++,a[r+1]-- ,需要计算区间内所有值时,进行一次前缀和即可

 

 

 

你可能感兴趣的:(ACM)