E. Boring Segments

2021/9/6 23:40:02

本文主要是介绍E. Boring Segments,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

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


这篇关于E. Boring Segments的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程