CF1555E题解
-
分析
观察到题面是求最小极差,想到 two-pointers。
按 \(w_i\) 大小排序,然后发现一个子段的子段的答案肯定不优于原子段。
和CF1777C以及NOI2016区间一样,选取合法左端点然后选取最大合法右端点。
值得注意的是,本题要求首尾相接,所以为了避免选取的线段无交集,将 \(r\) 减一,这样两个线段若无缝隙必然首尾相交(将 \(l + 1\) 也可以)。思考如何判区间合法。
区间合法即区间内不存在 \(0\),因为 \(0\) 是最小的数了(右移左端点操作中减的点已经被加过了),所以最小值为 \(0\) 为存在 \(0\) 的充要条件。所以判区间最小值是否为 \(0\) 即可。
区间最小值可以使用线段树维护,总时间复杂度为 \(\mathcal{O(n \log n + n \log m)}\),可以通过本题。 -
代码
#include <iostream>
#include <algorithm>
using namespace std;
constexpr int MAXN(4000007);
constexpr int INF(0x3f3f3f3f);
int minn[MAXN], lazy[MAXN];
int n, m, ans(INF);
struct node{
int l, r, w;
friend bool operator < (node x, node y) { return x.w < y.w;}
}a[MAXN];
inline void read(int &temp) { cin >> temp; }
struct SGT{
#define ls (p << 1)
#define rs (p << 1 | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p) { minn[p] = min(minn[ls], minn[rs]); }
inline void pushdown(int p) {
minn[ls] += lazy[p], minn[rs] += lazy[p];
lazy[ls] += lazy[p], lazy[rs] += lazy[p];
lazy[p] = 0;
}
void update(int p, int l, int r, int s, int t, int val) {
if (s <= l && t >= r) return lazy[p] += val, minn[p] += val, void();
if (lazy[p]) pushdown(p);
if (s <= mid) update(ls, l, mid, s, t, val);
if (t > mid) update(rs, mid + 1, r, s, t, val);
pushup(p);
}
}Miku;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
read(m), read(n);
for (int i(1); i <= m; ++i) read(a[i].l), read(a[i].r), read(a[i].w);
sort(a + 1, a + m + 1);
int r(0), l(1);
while (1) {
while (!minn[1] && r < m) ++r, Miku.update(1, 1, n - 1, a[r].l, a[r].r - 1, 1);
if (!minn[1] && r == m) break;
while (minn[1] && l <= r) Miku.update(1, 1, n - 1, a[l].l, a[l].r - 1, -1), ++l;
ans = min(ans, a[r].w - a[l - 1].w);
}
cout << ans << endl;
return 0;
}