CF EDU 112 E - Boring Segments

E - Boring Segments

线段树 + 双指针

题意:有一些线段,每条线段有权值,能把整个区间覆盖住的集合为好集合,求好集合中线段的最大权值 - 最小权值的最小值

首先关于线段覆盖区间的问题,可化段为点,覆盖了一个点视为覆盖了这个点和它右边的长度为 1 的段,因此覆盖了 \([l,r]\) 即为覆盖了 \([l,r-1]\) 的所有点,所以一开始把区间右端点 --,每个线段右端点 --

将线段按权值从小到大排序,可用双指针判断当前的线段集合能否覆盖住整个区间

枚举线段下标右端点,找到最大的左端点满足可以覆盖住区间,更新答案,易知左端点不会回退,所以可以双指针

判断当前线段集合能否覆盖 住整个区间可用线段树维护 :区间加,区间最小值;当 \([1,m]\) 的最小值不为 \(0\) 就是可用

双指针模板:

for (int l = 1, r = 1; r <= n; r++)
{
    while(l <= r && check(l, r))
    {
        //操作
        l++;
	}
        
}
#include <iostream>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 3e5 + 10, M = 1e6 + 10;
const ll INF = 1e18;
struct Seg
{
	int l, r;
	ll w;
	bool operator<(const Seg &x) const
	{
		return w < x.w;
	}
}a[N];
struct Node
{
	int l, r;
	ll add, minn;
}tr[M*4];
int n, m;
void pushup(int u)
{
	tr[u].minn = min(tr[u<<1].minn, tr[u<<1|1].minn);
}

void pushdown(int u)
{
	Node &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
	if (root.add)
	{
		left.add += root.add, right.add += root.add;
		left.minn += root.add;
		right.minn += root.add;
		root.add = 0;
	}
}

void build(int u, int l, int r)
{
	if (l == r)
	{
		tr[u] = {l, r, 0, 0};
		return;
	}
	tr[u] = {l, r, 0, 0};
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	pushup(u);
}

ll query(int u, int l, int r)
{
	if (tr[u].l >= l && tr[u].r <= r)
	{
		return tr[u].minn;
	}
	pushdown(u);
	ll v = INF;
	int mid = tr[u].l + tr[u].r >> 1;
	if (l <= mid)
		v = query(u << 1, l, r);
	if (r > mid)
		v = min(v, query(u << 1 | 1, l, r));
	return v;
}

void modify(int u, int l, int r, int k)
{
	if (tr[u].l >= l && tr[u].r <= r)
	{
		tr[u].add += k;
		tr[u].minn += k;
		return;
	}
	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	if (l <= mid)
		modify(u << 1, l, r, k);
	if (r > mid)
		modify(u << 1 | 1, l, r, k);
	pushup(u);
}

int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	m--;
	
	for (int i = 1; i <= n; i++)
	{
		int l, r;
		ll w;
		cin >> l >> r >> w;
		r--;
		a[i] = {l, r, w};
	}
	
	sort(a + 1, a + n + 1);
	build(1, 1, m);
	
	ll ans = INF;
	
	for (int L = 1, R = 1; R <= n; R++)
	{
		modify(1, a[R].l, a[R].r, 1);
		while(L <= R && query(1, 1, m))
		{
			ans = min(ans, a[R].w - a[L].w);
			modify(1, a[L].l, a[L].r, -1);
			L++;
		}
	}
	
	cout << ans << endl;
	return 0;
}
posted @ 2022-05-12 21:47  hzy0227  阅读(18)  评论(0编辑  收藏  举报