[CF2042D] Recommendations

推一推
题目传送门

假设要求第 \(i\) 个用户的强烈推荐的曲目数。那么对于所有曲目,因为是 \(i\) 的所有预测器都喜欢这首曲目才算答案,也就是求完全包含 \(i\) 的区间的交

那怎么算完全包含的区间呢?

可以先把这些区间 \(\left [l_i, r_i \right ]\) 排序,\(r\) 不一样就按 \(r\) 从小到大排,\(r\) 一样就按 \(l\) 从大到小排,再从后往前扫。

设扫到了第 \(i\) 个区间 \(\left [l_i, r_i \right ]\),一个完全包含 \(i\) 的区间 \(j\) 满足 \(l_i \ge l_j \wedge r_i \le r_j\),那么可以开两个线段树,一个存 \(l\) 的最大值,一个存 \(r\) 的最小值。

每算完一个答案,在第一个线段树的 \(l_i\) 位置改为 \(l_i\),第二个线段树的 \(l_i\) 位置改为 \(r_i\)

那么完全包含 \(i\) 的区间 \(l\) 的最大值就是第一个线段树中 \(\left [1,l_i \right ]\) 的最大值,\(r\) 的最小值就是第一个线段树中 \(\left [1,l_i \right ]\) 的最小值,最小 \(r\) 减最大 \(l\) 就是答案。

note: 离散化后要特判线段树里是正无穷和负无穷。

为了展开 atcoder 的库函数,码长快 300 行。

#include <bits/stdc++.h>

#include <algorithm>
#include <cassert>
#include <functional>
#include <vector>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#if __cplusplus >= 202002L
#include <bit>
#endif

namespace atcoder
{

    namespace internal
    {

#if __cplusplus >= 202002L

        using std::bit_ceil;

#else

        unsigned int bit_ceil(unsigned int n)
        {
            unsigned int x = 1;
            while (x < (unsigned int)(n))
                x *= 2;
            return x;
        }

#endif

        int countr_zero(unsigned int n)
        {
#ifdef _MSC_VER
            unsigned long index;
            _BitScanForward(&index, n);
            return index;
#else
            return __builtin_ctz(n);
#endif
        }

        constexpr int countr_zero_constexpr(unsigned int n)
        {
            int x = 0;
            while (!(n & (1 << x)))
                x++;
            return x;
        }

    } // namespace internal

} // namespace atcoder

namespace atcoder
{

#if __cplusplus >= 201703L

    template <class S, auto op, auto e>
    struct segtree
    {
        static_assert(std::is_convertible_v<decltype(op), std::function<S(S, S)>>,
                      "op must work as S(S, S)");
        static_assert(std::is_convertible_v<decltype(e), std::function<S()>>,
                      "e must work as S()");

#else

    template <class S, S (*op)(S, S), S (*e)()>
    struct segtree
    {

#endif

    public:
        segtree() : segtree(0) {}
        explicit segtree(int n) : segtree(std::vector<S>(n, e())) {}
        explicit segtree(const std::vector<S> &v) : _n(int(v.size()))
        {
            size = (int)internal::bit_ceil((unsigned int)(_n));
            log = internal::countr_zero((unsigned int)size);
            d = std::vector<S>(2 * size, e());
            for (int i = 0; i < _n; i++)
                d[size + i] = v[i];
            for (int i = size - 1; i >= 1; i--)
            {
                update(i);
            }
        }

        void set(int p, S x)
        {
            assert(0 <= p && p < _n);
            p += size;
            d[p] = x;
            for (int i = 1; i <= log; i++)
                update(p >> i);
        }

        S get(int p) const
        {
            assert(0 <= p && p < _n);
            return d[p + size];
        }

        S prod(int l, int r) const
        {
            assert(0 <= l && l <= r && r <= _n);
            S sml = e(), smr = e();
            l += size;
            r += size;

            while (l < r)
            {
                if (l & 1)
                    sml = op(sml, d[l++]);
                if (r & 1)
                    smr = op(d[--r], smr);
                l >>= 1;
                r >>= 1;
            }
            return op(sml, smr);
        }

        S all_prod() const { return d[1]; }

        template <bool (*f)(S)>
        int max_right(int l) const
        {
            return max_right(l, [](S x)
                             { return f(x); });
        }
        template <class F>
        int max_right(int l, F f) const
        {
            assert(0 <= l && l <= _n);
            assert(f(e()));
            if (l == _n)
                return _n;
            l += size;
            S sm = e();
            do
            {
                while (l % 2 == 0)
                    l >>= 1;
                if (!f(op(sm, d[l])))
                {
                    while (l < size)
                    {
                        l = (2 * l);
                        if (f(op(sm, d[l])))
                        {
                            sm = op(sm, d[l]);
                            l++;
                        }
                    }
                    return l - size;
                }
                sm = op(sm, d[l]);
                l++;
            } while ((l & -l) != l);
            return _n;
        }

        template <bool (*f)(S)>
        int min_left(int r) const
        {
            return min_left(r, [](S x)
                            { return f(x); });
        }
        template <class F>
        int min_left(int r, F f) const
        {
            assert(0 <= r && r <= _n);
            assert(f(e()));
            if (r == 0)
                return 0;
            r += size;
            S sm = e();
            do
            {
                r--;
                while (r > 1 && (r % 2))
                    r >>= 1;
                if (!f(op(d[r], sm)))
                {
                    while (r < size)
                    {
                        r = (2 * r + 1);
                        if (f(op(d[r], sm)))
                        {
                            sm = op(d[r], sm);
                            r--;
                        }
                    }
                    return r + 1 - size;
                }
                sm = op(d[r], sm);
            } while ((r & -r) != r);
            return 0;
        }

    private:
        int _n, size, log;
        std::vector<S> d;

        void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    };

} // namespace atcoder

#define int long long
using namespace std;
using namespace atcoder;
inline int read()
{
    int f = 0, ans = 0;
    char c = getchar();
    while (!isdigit(c))
        f |= c == '-', c = getchar();
    while (isdigit(c))
        ans = (ans << 3) + (ans << 1) + c - 48, c = getchar();
    return f ? -ans : ans;
}
void write(int x)
{
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
const int N = 4e5 + 5, M = N * 20, inf = 1e18, mod = 1e9 + 7;
int n, cnt, b[N], ans[N];
struct que
{
    int l, r, id;
    bool operator<(const que &rhs) const { return r == rhs.r ? l > rhs.l : r < rhs.r; }
} a[N];
signed main()
{
    // freopen(".in", "r", stdin);
    // freopen(".out", "w", stdout);
    int T = read();
    while (T--)
    {
        n = read(), cnt = 0;
        for (int i = 1; i <= n; ++i)
            a[i] = {read(), read(), i},
            b[++cnt] = a[i].l, b[++cnt] = a[i].r;
        sort(a + 1, a + n + 1);
        sort(b + 1, b + cnt + 1);
        cnt = unique(b + 1, b + cnt + 1) - b - 1;
        segtree<int, [](int a, int b)
                { return max(a, b); }, []()
                { return -inf; }>
            pre(cnt + 1);
        segtree<int, [](int a, int b)
                { return min(a, b); }, []()
                { return inf; }>
            suf(cnt + 1);
        a[n + 1] = {0, 0, 0};
        for (int i = n; i; --i)
        {
            auto &[l, r, id] = a[i];
            l = lower_bound(b + 1, b + cnt + 1, l) - b;
            r = lower_bound(b + 1, b + cnt + 1, r) - b;
            if (l != a[i + 1].l || r != a[i + 1].r)
            {
                int pr = pre.prod(1, l + 1), su = suf.prod(1, l + 1);
                if (pr != -inf && su != inf)
                    ans[id] = b[su] - b[pr] - (b[r] - b[l]);
                pre.set(l, l), suf.set(l, r);
            }
            else
                ans[a[i + 1].id] = 0;
        }
        for (int i = 1; i <= n; ++i)
            write(ans[i]), putchar('\n'), ans[i] = 0;
    }
    return 0;
}
posted @ 2024-12-21 17:31  SilverLi  阅读(10)  评论(0编辑  收藏  举报