[COGS247] 售票系统 - 线段树懒标记


题目描述

某次列车经C个城市,城市编号依次为1到C,列车上共有S个座位,铁路局规定售出的车票只能是坐票,即车上所有的旅客都有座。售票系统是由计算机执行的,每一个售票申请包含三个参数,分别用O,D,N表示,O为起始,D为目的地站,N为车票张数。售票系统对该售票申请作出受理和不受理的决定,只有在从O到D的区段内列车上都有N个和N个以上的空座位时该售票申请才被受理。
请你写一个程序,实现这个自动售票系统。


输入格式

输入第一行包含三个用空格隔开的整数C,S和R,其中1 <= C <= 60000,1 <= S <= 60000,1 <= R <= 60000,C为城市个数,S为列车上的座位数,R为所有售票申请总数。
接下来的R行每行为一个售票申请,用三个空格隔开的整数O,D和N表示,O为起始站,D为目的站,N为车票数,其中1<=C<=D,1<=O<=C,所有的售票申请按申请的时间从早到晚给出。


输出格式

输出共有R行,每行输出一个”YES”或”NO”,表示当前的售票申请被受理或不受理


样例数据

样例输入

4 6 4
1 4 2
1 3 2
2 4 3
1 2 3

样例输出

YES
YES
NO
NO


题目分析

线段树区间修改区间查询
维护车上剩余空位的最小值
lazy表示坐上车的人数(懒标记)
seat表示空位数


源代码

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
    int num=0,bj=1;
    char x=getchar();
    while(x<'0'||x>'9') {
        if(x=='-')bj=-1;
        x=getchar();
    }
    while(x>='0'&&x<='9') {
        num=num*10+x-'0';
        x=getchar();
    }
    return num*bj;
}
const int maxn=60000;
struct Tree { //修改区间 查询区间(+懒标记)
    int left,right,lazy,seat; //seat表示空位数 lazy表示在父亲结点累积的乘客 
};
struct Segment_Tree { //维护空位查询最小值
    Tree tree[maxn*4];
    int minn;
    void build(int index,int Left,int Right,int Seat) {
        tree[index].left=Left;
        tree[index].right=Right;
        tree[index].lazy=0;
        tree[index].seat=Seat;
        if(Left==Right)return;
        int mid=(Left+Right)/2;
        build(2*index,Left,mid,Seat);
        build(2*index+1,mid+1,Right,Seat);
    }
    void push_down(int index) { //标记下传,下传当前lazy(标记为0不下传)
        if(tree[index].lazy==0)return;
        tree[2*index].seat-=tree[index].lazy;
        tree[2*index+1].seat-=tree[index].lazy;
        tree[2*index].lazy+=tree[index].lazy;
        tree[2*index+1].lazy+=tree[index].lazy;
        tree[index].lazy=0;
    }
    void push_up(int index) { //标记上传,合并子树信息
        tree[index].seat=min(tree[index*2].seat,tree[index*2+1].seat);
    }
    void modify(int index,int Left,int Right,int data) { //减去data
        if(Right<tree[index].left||Left>tree[index].right)return; //不相交
        if(Left<=tree[index].left&&Right>=tree[index].right) { //完全包含
            tree[index].seat-=data;
            tree[index].lazy+=data;
            return;
        }
        push_down(index); //标记下传
        modify(index*2,Left,Right,data);
        modify(index*2+1,Left,Right,data);
        push_up(index); //标记上传
    }
    void init() {
        minn=0x7fffffff/2;
    }
    void Query(int index,int Left,int Right) {
        if(Right<tree[index].left||Left>tree[index].right)return; //不相交
        if(Left<=tree[index].left&&Right>=tree[index].right) { //完全包含
            minn=min(minn,tree[index].seat);
            return;
        }
        push_down(index);
        Query(index*2,Left,Right);
        Query(index*2+1,Left,Right);
        push_up(index);
    }
};
Segment_Tree st;
int n,Seat,m;
int main() {
    n=Get_Int();
    Seat=Get_Int();
    m=Get_Int();
    st.build(1,1,n,Seat);
    for(int i=1; i<=m; i++) {
        int Left=Get_Int(),Right=Get_Int()-1,data=Get_Int();
        st.init();
        st.Query(1,Left,Right);
        if(st.minn>=data) {
            st.modify(1,Left,Right,data);
            puts("YES");
        } else puts("NO");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值