[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;
}