借教室

线段树+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.

今天就这样了。

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值