借教室(差分数组+二分)
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 <bits/stdc++.h>
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]-- ,需要计算区间内所有值时,进行一次前缀和即可