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