[Trick] 折半报警器

[Trick] 折半报警器

以例题来举例:

这个Link里面的 T3。

很明显,对于一个类型 \(1\) 的操作,由抽屉原理,一定会有一个点会超过 \(\lfloor \frac{y}{k} \rfloor\) ,考虑将这个东西当作一个阈值,当其中的一个数变化大于 \(\lfloor \frac{y}{k} \rfloor\) 的时候,我们计算一共此时总数变化了多少,再重构一下就可以。

分析一下时间复杂度,我们发现每一次对于一个类型 \(1\) 的操作,会将总数至少减去 \(\frac{1}{k}\),综合下来重构次数为 \(\log_{\frac{k}{k-1}} y\)

上一下代码:

#include <bits/stdc++.h>
#define FASTIO                   \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0);
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int N = 2e5 + 5;
struct Task {
    ll target;
    int k;
    int machines[5];
    bool finished;
} tasks[N];
struct node {
    ll tim;
    int id;
    int ver;
    bool operator>(const node& o) const { return tim > o.tim; }
};
ll mtime[N];
int task_ver[N];
priority_queue<node, vector<node>, greater<node>> pq[N];
void update(int id, vector<int>& vec) {
    if (tasks[id].finished)
        return;
    ll sum = 0;
    for (int i = 0; i < tasks[id].k; ++i) {
        sum += mtime[tasks[id].machines[i]];
    }
    if (sum >= tasks[id].target) {
        tasks[id].finished = true;
        vec.push_back(id);
    } else {
        ll rem = tasks[id].target - sum;
        ll step = (rem + tasks[id].k - 1) / tasks[id].k;
        task_ver[id]++;
        for (int i = 0; i < tasks[id].k; ++i) {
            int ano = tasks[id].machines[i];
            pq[ano].push({ mtime[ano] + step, id, task_ver[id] });
        }
    }
}
int main() {
    FASTIO;
    freopen("mission.in", "r", stdin);
    freopen("mission.out", "w", stdout);
    int n, m;
    cin >> n >> m;
    int cnt_task = 1;
    int lst = 0;
    for (int i = 1; i <= m; ++i) {
        int op;
        cin >> op;
        if (op == 1) {
            ll y;
            int k;
            cin >> y >> k;
            y ^= lst;
            tasks[cnt_task].target = y;
            tasks[cnt_task].k = k;
            tasks[cnt_task].finished = false;
            ll sum = 0;
            for (int j = 0; j < k; ++j) {
                int q;
                cin >> q;
                q ^= lst;
                tasks[cnt_task].machines[j] = q;
                sum += mtime[q];
            }
            tasks[cnt_task].target += sum;
            vector<int> vec;
            update(cnt_task++, vec);
        } else {
            int x;
            ll y;
            cin >> x >> y;
            x ^= lst;
            y ^= lst;
            mtime[x] += y;
            vector<int> vec;
            while (!pq[x].empty() && pq[x].top().tim <= mtime[x]) {
                node e = pq[x].top();
                pq[x].pop();
                if (tasks[e.id].finished || e.ver != task_ver[e.id])
                    continue;
                update(e.id, vec);
            }
            sort(vec.begin(), vec.end());
            cout << vec.size() << ' ';
            for (int id : vec) cout << id << ' ';
            cout << "\n";
            lst = (int)vec.size();
        }
    }
    return 0;
}
posted @ 2026-05-21 14:57  To_string  阅读(4)  评论(0)    收藏  举报