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;
}
posted @ 2023-10-26 08:58  Kazdale  阅读(173)  评论(0编辑  收藏  举报