E. Boring Segments
https://codeforces.com/contest/1555/problem/E
题目大意
给出\(n\)个区间的端点,和每个区间的价值,问你选择一些区间可以从 \(1\)走到\(m\)的最小花费。
只有区间有交集才可以互通,即:\([1,2]和[2,3]\)可以,但是\([1,2]和[3,4]\)是不能互通的。最小花费的定义是所选区间中的最大价值和最小价值之差。
解题思路
可以考虑尺取的思路。
因为这个题区间之间需要覆盖,但是覆盖问题不好处理,我们可以将 \(m\)和每个线段的右断点减\(1\),这样区间只要连续就满足条件了。
我们用线段树维护一个区间的最小值,每次选择一个区间就是将该线段的区间在线段树中加\(1\),然后查看\(1\)到\(m\)中的最小值是否是\(1\)即可判断所选区间是否覆盖\(1\)到\(m\),因为我们所选的区间在经过按权值排序后越连续越优(因为答案不受中间值影响,只与最左边和最右边值的影响),所以可以使用双指针每次让左端点尽可能右移,右端点相当于一个遍历的过程。
所以首先将线段按权值排序,然后从\(1\)到\(n\)扫一遍,当遍历到\(i\)时,首先将\(i\)这段区间在线段树中加\(1\),随后判断\(l\)是否可以右移,每次右移前更新答案即可,右移后将对应区间在线段树中减\(1\)。
Code
#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
#define V vector
#define int ll
using namespace std;
const int N = 1e6 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
struct ${
int l,r,w;
bool operator < ($ p)const{
if(w!=p.w)return w < p.w;
else if(r != p.r)return r < p.r;
else return l < p.l;
}
}a[N];
struct T{
int l,r,mid,mi,sum,lz;
}tree[N << 2];
void pushup(int rt){
tree[rt].mi = min(tree[rt<<1].mi,tree[rt<<1|1].mi);
}
void pushdown(int rt){
if(tree[rt].lz != 0){
tree[rt<<1].lz += tree[rt].lz;
tree[rt<<1].mi += tree[rt].lz;
tree[rt<<1|1].lz += tree[rt].lz;
tree[rt<<1|1].mi += tree[rt].lz;
tree[rt].lz = 0;
}
}
void build(int l,int r,int rt){
tree[rt].l = l;
tree[rt].r = r;
int mid = (l + r) >> 1;
tree[rt].mid = mid;
tree[rt].mi = tree[rt].lz = 0;
if(l == r){
return;
}
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
void update(int l,int r,int v,int rt){
if(l <= tree[rt].l && tree[rt].r <= r){
tree[rt].lz += v;
tree[rt].mi += v;
return;
}
pushdown(rt);
if(l <= tree[rt].mid)
update(l,r,v,rt<<1);
if(r > tree[rt].mid)
update(l,r,v,rt<<1|1);
pushup(rt);
}
int query(int l,int r,int rt){
if(l <= tree[rt].l && tree[rt].r <= r){
return tree[rt].mi;
}
pushdown(rt);
int ret = 1e9;
if(l <= tree[rt].mid)
ret = min(ret, query(l,r,rt<<1));
if(r > tree[rt].mid)
ret = min(ret, query(l,r,rt<<1|1));
return ret;
}
void solve(){
int n,m;
cin >> n >> m;
m--;
int maxn = 0;
for(int i = 1; i <= n; i++){
cin >> a[i].l >> a[i].r >> a[i].w;
maxn = max(maxn,a[i].r);
a[i].r --;
}
build(1,maxn,1);
sort(a+1,a+1+n);
int l = 1;
int ans = 1e9;
for(int i = 1; i <= n; i++)
{
update(a[i].l,a[i].r,1,1);
while(l <= i && query(1,m,1)){
ans = min(ans,a[i].w - a[l].w);
update(a[l].l,a[l].r,-1,1);
l++;
}
}
cout << ans << "\n";
}
signed main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
qc;
int T = 1;
//cin >> T;
while(T--){
solve();
}
return 0;
}