线段树+lazy
题目介绍:
在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。
教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。面对海量租借教室的信息,我们自然希望编程解决这个问题。
我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。
如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第sj天到第tj天中有至少一天剩余的教室数量不足dj个。现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。
———————————分割—————————————-
输入:
输入文件为 classroom.in。第一行包含两个正整数n, m,表示天数和订单的数量。
第二行包含n个正整数,其中第i个数为ri,表示第i天可用于租借的教室数量。
接下来有m行,每行包含三个正整数dj, sj, tj ,表示租借的数量,租借开始、结束分别在第几天。每行相邻的两个数之间均用一个空格隔开。
天数与订单均用从1开始的整数编号。
输出:
输出文件为 classroom.out。
如果所有订单均可满足,则输出只有一行,包含一个整数 0。
否则(订单无法完全满足)输出两行,第一行输出一个负整数-1,第二行输出需要修改订单的申请人编号。
样例输入:
4 3 2 5 4 3 2 1 3 3 2 4 4 2 4
样例输出:
-1 2
数据范围:
对于 10%的数据,有1 ≤ n, m ≤ 10;
对于 30%的数据,有1 ≤ n, m ≤ 1000;
对于 70%的数据,有1 ≤ n, m ≤ 10^5;
对于 100%的数据,有1 ≤ n, m ≤ 10^6, 0 ≤ ri, dj≤ 10^9, 1 ≤ sj≤ tj≤ n。
—往下看
把题目抽空后:
给你一组数字,动态的对一段区间内的数减去一个值,只要这组数里出现了一个负数,就可以输出答案。
——-思路——-
动态的去除一段数,明显就是可以考虑线段树,树状数组一类的区间维护。
——-告诉你解法——-
解法一:二分+前缀和,可以稳过。(此方法我可没想,可以参考其他大牛。)
解法二:线段树+lazy,对于此题几乎可以过,但常数有些大,就有风险了。
——-解法二——-
用线段树维护这个区间,每次对一段区间进行操作时,打下lazy标记,对于每个询问只需要查询tree[1].min值就可以了。
以下为free pascal代码。
type
cy=record
value,labe:int64;
end;
const maxn=1000005;
var
a:array[0..maxn]of longint;
tree:array[0..4*maxn]of cy;
i,x,y,z,ans,n,m:longint;
function
min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
procedure
maketree(p,l,r:longint);
var
mid:longint;
begin
if l=r then
begin
tree[p].value:=a[l];
tree[p].labe:=0;
exit;
end;
tree[p].labe:=0;
mid:=(l+r)>>1;
maketree(p*2,l,mid);
maketree(p*2+1,mid+1,r);
tree[p].value:=min(tree[p<<1].value,tree[p<<1+1].value);
tree[p].labe:=0;
end;
procedure
push(p:longint;x:int64);
begin
inc(tree[p<<1].labe,x);
inc(tree[p<<1+1].labe,x);
dec(tree[p<<1].value,x);
dec(tree[p<<1+1].value,x);
end;
procedure
change(p,l,r,a,b,take:longint);
var
mid:longint;
begin
if (l=a)and(r=b) then
begin
tree[p].value:=tree[p].value-take;
tree[p].labe:=tree[p].labe+take;
exit;
end;
push(p,tree[p].labe);
tree[p].labe:=0;
mid:=(l+r)>>1;
if b<=mid then change(p*2,l,mid,a,b,take)
else if a>mid then change(p*2+1,mid+1,r,a,b,take)
else
begin
change(p*2,l,mid,a,mid,take);
change(p*2+1,mid+1,r,mid+1,b,take);
end;
tree[p].value:=min(tree[p<<1].value,tree[p<<1+1].value);
end;
begin
assign(input,'class.in'); reset(input);
assign(output,'class.out'); rewrite(output);
readln(n,m);
for i:=1 to n do read(a[i]);
maketree(1,1,n);
for i:=1 to m do
begin
readln(z,x,y);
change(1,1,n,x,y,z);
ans:=tree[1].value;
if ans<0 then
begin
writeln(-1);
writeln(i);
halt;
end;
end;
writeln(0);
close(input); close(output);
end.