题意

$n$ 个区间,选 $m$ 个,使得最大区间长度减去最小区间长度最小。

$n\leq5\times 10^5,m\leq2\times10^5$

题解

按区间长度排序,然后双指针扫区间,右指针扫当前选的大区间,左指针扫小区间。对于当前已选数量,用线段树维护。

代码

const int N = 5e5 + 3;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n, m;
	struct SGT {
		struct node {
			int l, r, val, tag;
		} t[N << 4];
#define lson p << 1
#define rson p << 1 | 1
		void build (int p, int l, int r) {
			t[p].l = l, t[p].r = r;
			if (t[p].l == t[p].r) {
				t[p].val = 0;
				return ;
			}
			int mid = (t[p].l + t[p].r) >> 1;
			build (lson, l, mid);
			build (rson, mid + 1, r);
			t[p].val = 0;
		}
		void pushdown (int p) {
			if (!t[p].tag) return;
			t[lson].tag += t[p].tag;
			t[lson].val += t[p].tag;
			t[rson].tag += t[p].tag;
			t[rson].val += t[p].tag;
			t[p].tag = 0;
			return ;
		}
		void modify (int p, int l, int r, int val) {
			if (l <= t[p].l && t[p].r <= r) {
				t[p].tag += val;
				t[p].val += val;
				return ;
			}
			pushdown(p);
			int mid = (t[p].l + t[p].r) >> 1;
			if (l <= mid) modify(lson, l, r, val);
			if (r > mid) modify(rson, l, r, val);
			t[p].val = max(t[lson].val, t[rson].val);
		}
	}t;
	struct Segment {
		int l, r, len;
		Segment (int l = 0, int r = 0):l(l), r(r) { len = r - l; }
		bool operator < (const Segment &a) const {
			return len == a.len? l < a.l: len < a.len;
		}
	}sg[N];
	int b[N << 1], tot;
	int ans = 0x3f3f3f3f;
	int main() {
		n = Read(), m = Read();
		for (int i = 1; i <= n; i++) {
			int l = Read(), r = Read();
			sg[i] = Segment(l, r);
			b[++tot] = l; b[++tot] = r;
		}
		sort (sg + 1, sg + 1 + n);
		sort (b + 1, b + 1 + tot);
		tot = unique(b + 1, b + 1 + tot) - b - 1;
		for (int i = 1; i <= n; i++) {
			sg[i].l = lower_bound(b + 1, b + 1 + tot, sg[i].l) - b;
			sg[i].r = lower_bound(b + 1, b + 1 + tot, sg[i].r) - b;
		}
		t.build(1, 1, (N - 3) << 1);
		for (int l = 1, r = 1; r <= n; r++) {
			t.modify(1, sg[r].l, sg[r].r, 1);
			for (; t.t[1].val >= m && l <= r; l++) {
				ans = min(ans, sg[r].len - sg[l].len);
				t.modify(1, sg[l].l, sg[l].r, -1);
			}
		}
		if (ans == 0x3f3f3f3f) ans = -1;
		printf ("%d\n", ans);
		return 0;
	}
}

int main() {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2023-11-08 07:35:38
博客类型