首页 > 其他分享 >NC24961 Hotel

NC24961 Hotel

时间:2023-05-02 23:12:50浏览次数:55  
标签:remp return NC24961 Hotel len int 区间 lemp

题目链接

题目

题目描述

The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 ≤ N ≤ 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).
The cows and other visitors arrive in groups of size Di (1 ≤ Di ≤ N) and approach the front desk to check in. Each group i requests a set of Di contiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+Di-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.
Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters Xi and Di which specify the vacating of rooms Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1). Some (or all) of those rooms might be empty before the checkout.
Your job is to assist Canmuu by processing M (1 ≤ M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.

输入描述

  • Line 1: Two space-separated integers: N and M
  • Lines 2..M+1: Line i+1 contains request expressed as one of two possible formats: (a) Two space separated integers representing a check-in request: 1 and Di (b) Three space-separated integers representing a check-out: 2, Xi, and Di

输出描述

  • Lines 1.....: For each check-in request, output a single line with a single integer r, the first room in the contiguous sequence of rooms to be occupied. If the request cannot be satisfied, output 0.

示例1

输入

10 6
1 3
1 3
1 3
1 3
2 5 5
1 6

输出

1
4
7
0
5

题解

知识点:线段树,二分。

考虑连续区间的权值最大值,需要维护三个信息,区间连续空房个数 \(emp\) 、区间从左端点开始的连续空房个数 \(lemp\) 、区间从右端点开始的连续空房的个数 \(remp\) 。

合并时, \(mx\) 为左右子区间 \(mx\) 和左子区间 \(remp\) 加右子区间 \(lemp\) 之和取最大值。 \(lemp,remp\) 需要考虑跨越左右区间的特殊情况,因此需要维护区间长度 \(len\) 。例如,若左子区间的 \(lemp\) 等于左子区间的 \(len\) ,那么区间 \(lemp\) 就是左子区间 \(len\) 加右子区间 \(lemp\) 否则继承左子区间的 \(lemp\) 即可,区间 \(remp\) 同理。

因此,区间信息需要维护 \(len,emp,lemp,remp\) 。

接下来是查找第一个连续空位大于等于 \(val\) 的位置,利用线段树上二分即可解决。首先判断是否存在,之后分三类情况:

  1. 若左子区间 \(emp\) 大于等于 \(val\) ,则查询左子区间。
  2. 否则若跨越左右子区间的空位,即左子区间的 \(remp\) 加右子区间的 \(lemp\) 之和,大于等于 \(val\) ,则直接返回位置。
  3. 否则查询右子区间。

区间修改维护一个信息,修改种类 \(upd\) , 有三个值 \(0/1/-1\) 表示未修改、全部入住、全部离开。 修改很朴素,看代码就行。

时间复杂度 \(O((n+m) \log n)\)

空间复杂度 \(O(n)\)

代码

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

struct T {
    int len;
    int lemp, remp;
    int emp;
    static T e() { return{ 0,0,0,0 }; }
    friend T operator+(const T &a, const T &b) {
        return{
            a.len + b.len,
            a.lemp == a.len ? a.len + b.lemp : a.lemp,
            b.remp == b.len ? a.remp + b.len : b.remp,
            max({a.emp,b.emp,a.remp + b.lemp})
        };
    }
};

struct F {
    int upd;
    static F e() { return { 0 }; }
    T operator()(const T &x) {
        if (upd == 1)
            return{
                x.len,
                0,0,
                0
        };
        if (upd == -1)
            return{
                x.len,
                x.len,x.len,
                x.len
        };
        return x;
    }
    F operator()(const F &g) {
        return { upd ? upd : g.upd };
    }
};

class SegmentTreeLazy {
    int n;
    vector<T> node;
    vector<F> lazy;

    void push_down(int rt) {
        node[rt << 1] = lazy[rt](node[rt << 1]);
        lazy[rt << 1] = lazy[rt](lazy[rt << 1]);
        node[rt << 1 | 1] = lazy[rt](node[rt << 1 | 1]);
        lazy[rt << 1 | 1] = lazy[rt](lazy[rt << 1 | 1]);
        lazy[rt] = F::e();
    }

    void update(int rt, int l, int r, int x, int y, F f) {
        if (r < x || y < l) return;
        if (x <= l && r <= y) return node[rt] = f(node[rt]), lazy[rt] = f(lazy[rt]), void();
        push_down(rt);
        int mid = l + r >> 1;
        update(rt << 1, l, mid, x, y, f);
        update(rt << 1 | 1, mid + 1, r, x, y, f);
        node[rt] = node[rt << 1] + node[rt << 1 | 1];
    }

    int query(int rt, int l, int r, int val) {
        if (l == r) return l;
        push_down(rt);
        int mid = l + r >> 1;
        if (node[rt << 1].emp >= val) return query(rt << 1, l, mid, val);
        if (node[rt << 1].remp + node[rt << 1 | 1].lemp >= val) return mid - node[rt << 1].remp + 1;
        return query(rt << 1 | 1, mid + 1, r, val);
    }

public:
    SegmentTreeLazy(int _n = 0) { init(_n); }

    void init(int _n) {
        n = _n;
        node.assign(n << 2, T::e());
        lazy.assign(n << 2, F::e());

        function<void(int, int, int)> build = [&](int rt, int l, int r) {
            if (l == r) return node[rt] = { 1,1,1,1 }, void();
            int mid = l + r >> 1;
            build(rt << 1, l, mid);
            build(rt << 1 | 1, mid + 1, r);
            node[rt] = node[rt << 1] + node[rt << 1 | 1];
        };
        build(1, 1, n);
    }

    void update(int x, int y, F f) { update(1, 1, n, x, y, f); }

    int query(int val) {
        if (node[1].emp < val) return 0;
        return query(1, 1, n, val);
    }
};

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    SegmentTreeLazy sgt(n);
    while (m--) {
        int op;
        cin >> op;
        if (op == 1) {
            int d;
            cin >> d;
            int pos = sgt.query(d);
            if (pos) sgt.update(pos, pos + d - 1, { 1 });
            cout << pos << '\n';
        }
        else {
            int x, d;
            cin >> x >> d;
            sgt.update(x, x + d - 1, { -1 });
        }
    }
    return 0;
}

标签:remp,return,NC24961,Hotel,len,int,区间,lemp
From: https://www.cnblogs.com/BlankYang/p/17368495.html

相关文章

  • [USACO08FEB]Hotel G
    [USACO08FEB]HotelG线段树二分,最大字段和对于操作二,是很简单的区间赋值对于操作一,长度为\(len\)的,我们要找到最小的的\(x\)满足\([x,x+len-1]\)的房间为空在最大字段和的基础上,我们可以求出最长连续空房间的长度,对于要求长度为\(len\)的房间,可以按顺序判断:若左区......
  • [USACO08FEB]Hotel G 线段树区间合并|维护最长的连续1
    这个还是看代码,比讲的清楚#include<bits/stdc++.h>#definefastioios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)#definels(rt<<1)#definers(rt<<1|1......
  • 【洛谷】P5904 [POI2014]HOT-Hotels(长链剖分)
    原题链接题意给出一棵有\(n\)个点的树,求有多少组点\((i,j,k)\)满足\(i,j,k\)两两之间的距离都相等。\((i,j,k)\)与\((i,k,j)\)算作同一组。\(1\len\le10^5\)......
  • vulnhub靶场之WORST WESTERN HOTEL: 1
    准备:攻击机:虚拟机kali、本机win10。靶机:WorstWesternHotel:1,下载地址:https://download.vulnhub.com/worstwesternhotel/HotelWW.ova,下载后直接vbox打开即可。知识点:s......
  • How IoT can benefit smart hotels and the hospitality industry
    Roomserviceandmaintenancearekeycomponentsofsmarthotelmanagement.Notonlyaretheycriticaltokeepingavenuerunningsmoothly,butdependingonthe......
  • POJ 3667 Hotel(线段树:区间覆盖+维护最大连续子区间长度)
    HotelDescriptionThecowsarejourneyingnorthtoThunderBayinCanadatogainculturalenrichmentandenjoyavacationonthesunnyshoresofLakeSuperior.Be......
  • P2894 [USACO08FEB]Hotel G
    \(P2894\)[\(USACO08FEB\)]\(Hotel\)\(G\)一、题目描述参考样例,第一行输入\(n,m\),\(n\)代表有\(n\)个房间,编号为\(1-\simn\),开始都为空房,\(m\)表示以下有\(m\)行操作......
  • Luogu 2894 酒店Hotel
    题目链接:​​传送门​​题目描述:参考样例,第一行输入n(1≤n≤50,000),m(1≤M<50,000),n代表有n个房间,编号为1—n,开始都为空房,m表示以下有m行操作,以下每行先输入一个......
  • POJ 3667 Hotel
    题目链接:​​传送门​​虽然是重题但还是要发一篇博客维护最长01串oh我之前写的好良心再放上来#include<iostream>#include<cstdio>#include<cstring>#include<cstdli......
  • P2894 [USACO08FEB]Hotel G
    #include<bits/stdc++.h>usingnamespacestd;classsegment_tree{ public: intn,m; structtree{ intlen; intlm,rm; intmm; intlazy_tag; #d......