NOIP历年真题练习-提高组 借教室 (线段树模板题)

    科技2022-07-16  124

    题目链接:点此跳转

    题目大意:

    面对海量租借教室的信息,我们自然希望编程解决这个问题。

    我们需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借。共有m份订单,每份订单用三个正整数描述,分别为dj, sj, tj,表示某租借者需要从第sj天到第tj天租借教室(包括第sj天和第tj天),每天需要租借dj个教室。

    我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。

    借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第sj天到第tj天中有至少一天剩余的教室数量不足dj个。

    现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单

    解题思路:

    因为涉及到了多个区间查询和更改问题,我们很容易可以想到用线段树来解决此题,(有hxd用的二分+差分做的,代码也很巧妙,可以抽空学习一下),对于每次操作,我们可以先查询一下在规定区间里最小值是否小于要借的教室的数量,是的话直接输出-1和编号即可,否则的话更改区间,递归下一次。

    Code:

    #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1000005; typedef long long ll; int n,m,k; ll sum[maxn]; struct node{ int l,r; ll value,lazy; }tree[maxn<<2]; void push_up(int x){ tree[x].value=min(tree[x<<1].value,tree[x<<1|1].value); } void update(int x,ll w){ tree[x].value-=w; tree[x].lazy+=w; } void push_down(int x){ if(tree[x].lazy!=0){ update(x<<1,tree[x].lazy); update(x<<1|1,tree[x].lazy); tree[x].lazy=0; } } void bulid(int x,int l,int r){ tree[x].l=l; tree[x].r=r; if(l==r){ // scanf("%d",&tree[x].value); tree[x].value=sum[l]; tree[x].lazy=0; return ; } int mid=(l+r)>>1; bulid(x<<1,l,mid); bulid(x<<1|1,mid+1,r); push_up(x); } void change(int x,int l,int r,ll w){ if(tree[x].l>=l&&tree[x].r<=r){ update(x,w); return ; } push_down(x); int mid=(tree[x].l+tree[x].r)/2; if(r<=mid) change(x*2,l,r,w); else if(l>=mid+1) change(x*2+1,l,r,w); else{ change(x*2,l,mid,w); change(x*2+1,mid+1,r,w); } push_up(x); } int query(int x,int l,int r){ if(tree[x].l==l&&tree[x].r==r) return tree[x].value; push_down(x); int mid=(tree[x].l+tree[x].r)/2; if(r<=mid) return query(x<<1,l,r); else if(l>mid) return query(x<<1|1,l,r); else return min(query(x<<1,l,mid),query(x<<1|1,mid+1,r)); } int main() { scanf("%d%d",&n,&m); int cas=0; for(int i=1;i<=n;i++) scanf("%d",&sum[i]); bulid(1,1,n); for(int i=1;i<=m;i++){ ++cas; int x,l,r; scanf("%d%d%d",&x,&l,&r); int pos=query(1,l,r); if(pos<x){ cout<<-1<<"\n"<<cas<<"\n"; return 0; } change(1,l,r,x); } cout<<0<<"\n"; return 0; }
    Processed: 0.010, SQL: 8