售票系統 題解

jxyanglinus發表於2024-08-19

題目描述

某次列車途經 C 個城市,城市編號依次為 \(1\)\(C\),列車上共有 \(S\) 個座位,鐵路局規定售出的車票只能是坐票, 即車上所有的旅客都有座。售票系統是由計算機執行的,每一個售票申請包含三個引數,分別用 \(O,D,N\) 表示,\(O\) 為起始站,\(D\) 為目的地站,\(N\) 為車票張數。售票系統對該售票申請作出受理或不受理的決定,只有在從 \(O\)\(D\) 的區段內列車上都有 \(N\) 個或 \(N\) 個以上的空座位時該售票申請才被受理。

請你寫一個程式,實現這個自動 售票系統。

輸入格式

第一行包含三個用空格隔開的整數 \(C,S\)\(R\),其中 \(1 \le C \le 60000, 1 \le S \le 60000, 1 \le R \le 60000\)。C 為城市個數,S 為列車上的座位數,R 為所有售票申請總數。

接下來的 R 行每行為一個售票申請,用三個由空格隔開的整數 \(O,D\)\(N\) 表示,\(O\) 為起始站,\(D\) 為目的地站,\(N\) 為車票張數,其中 \(1 \le D \le C, 1 \le O \le C\),所有的售票申請按申請的時間從早到晚給出。

輸出格式

輸出共有 \(R\) 行,每行輸出一個 YESNO,表示當前的售票申請被受理或不被受理。

樣例

樣例輸入

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

樣例輸出

YES
YES
NO
NO

資料範圍與提示

對於 \(30\%\) 的資料,\(1 \le C \le 350, 1 \le S \le 200, 1 \le R \le 500\)

對於 \(100\%\) 的資料,\(1 \le C \le 60000, 1 \le S \le 60000, 1 \le R \le 60000\)

Analysis

  • 題目一眼線段樹。
  • 維護區間最小值,只有當所詢問的區間的最小值大於等於請求車票張數是才能同意申請,同時需要更新所詢問的區間的最小值。
  • 然而本題有一個坑點,就是乘客到了目的地後會下車,所以到車站後車上的人數會減少,故查詢和更新的區間應當為左閉右開區間 \([O, D)\)。(警鐘撅爛,考試時沒考慮到)

Code

#include <bits/stdc++.h>
using namespace std;

const int maxn = 60005;
int n, m, q;
struct SegmentTree {
    int left, right;
    int minv, tag;
} tree[maxn << 2];

inline void pushup(int root) {
    tree[root].minv = min(tree[root << 1].minv, tree[root << 1 | 1].minv);
}

inline void pushdown(int root) {
    if (!tree[root].tag) return;
    tree[root << 1].minv += tree[root].tag;
    tree[root << 1 | 1].minv += tree[root].tag;
    tree[root << 1].tag += tree[root].tag;
    tree[root << 1 | 1].tag += tree[root].tag;
    tree[root].tag = 0;
}

void build(int root, int l, int r) {
    tree[root].left = l;
    tree[root].right = r;
    if (l == r) {
        tree[root].minv = m;
        return;
    }
    int mid = (l + r) >> 1;
    build(root << 1, l, mid);
    build(root << 1 | 1, mid + 1, r);
    pushup(root);
}

void update(int root, int l, int r, int val) {
    if (l > r) return; // 好習慣:防止出現左端點大於右端點的情況
    if (tree[root].left >= l && tree[root].right <= r) {
        tree[root].minv += val;
        tree[root].tag += val;
        return;
    }
    pushdown(root);
    int mid = (tree[root].left + tree[root].right) >> 1;
    if (mid >= l) update(root << 1, l, r, val);
    if (mid < r) update(root << 1 | 1, l, r, val);
    pushup(root);
}

int query(int root, int l, int r) {
    if (l > r) return 0; // 好習慣:防止出現左端點大於右端點的情況
    if (tree[root].left >= l && tree[root].right <= r) {
        return tree[root].minv;
    }
    pushdown(root);
    int mid = (tree[root].left + tree[root].right) >> 1;
    int ans = 0x3f3f3f3f;
    if (mid >= l) ans = min(ans, query(root << 1, l, r));
    if (mid < r) ans = min(ans, query(root << 1 | 1, l, r));
    return ans;
}

int main() {
    // freopen("railway.in", "r", stdin);
    // freopen("railway.out", "w", stdout);
    scanf("%d%d%d", &n, &m, &q);
    build(1, 1, n);
    while (q--) {
        int l, r, val;
        scanf("%d%d%d", &l, &r, &val);
        int rest = query(1, l, r - 1);
        if (rest >= val) {
            printf("YES\n");
            update(1, l, r - 1, -val);
        } else {
            printf("NO\n");
        }
    }
    return 0;
}

本篇在洛谷部落格同步釋出。

相關文章