Educational Codeforces112 1555.E. Boring Segments(尺取+线段树)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Educational Codeforces112 1555.E. Boring Segments(尺取+线段树)相关的知识,希望对你有一定的参考价值。

LINK

题意

给出 n n n条线段,若两个点在同一条线段内,那么可以在这两个点间移动

现在你需要选择一个线段的子集,代价是选择的最大权值线段和最小权值线段的差

最小化代价(保证一定存在解)


把线段 [ l , r ] [l,r] [l,r]的作用看成可以连通 ( l , l + 1 ) , ( l + 1 , l + 2 ) . . . ( r − 1 , r ) (l,l+1),(l+1,l+2)...(r-1,r) (l,l+1),(l+1,l+2)...(r1,r)

那么从 1 1 1走到 m m m,意味着 i ∈ [ 1 , m − 1 ] i\\in[1,m-1] i[1,m1]都连通了 ( i , i + 1 ) (i,i+1) (i,i+1)

这样我们就把线段右端点都减去 1 1 1,求一个子集能覆盖 [ 1 , m − 1 ] [1,m-1] [1,m1]

要求最小化极差,我们可以用尺取的方法,先对线段的权值排序

然后尺取一段区间 [ L , R ] [L,R] [L,R],使得这 R − L + 1 R-L+1 RL+1条线段刚好能覆盖 [ 1 , m − 1 ] [1,m-1] [1,m1]

更新答案,然后移动区间.

于是问题变成如何动态维护当前尺取区间是否覆盖了 [ 1 , m − 1 ] [1,m-1] [1,m1]

对于每次加入的线段 [ l i , r i ] [l_i,r_i] [li,ri],我们把这个区间内所有数加上 1 1 1

如果覆盖了 [ 1 , m − 1 ] [1,m-1] [1,m1],那么每个点被覆盖的次数都大于 0 0 0,显然维护一个区间最小值即可

检查是否覆盖判一下 [ 1 , m − 1 ] [1,m-1] [1,m1]的区间最小值即可

这样就可以用线段树维护,区间修改,区间最小值

总体复杂度 O ( n ∗ l o g ( m ) ) O(n*log(m)) O(nlog(m))

#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define lson ls,l,mid
#define rson rs,mid+1,r
const int maxn = 3e5+10;
const int N = 4e6+10;
int n,m;
struct p
{
	int l,r,w;
	bool operator < ( const p&tmp )	const
	{
		return w<tmp.w;
	}
}a[maxn];
int laz[N],mi[N];
void pushdown(int rt,int l,int r)
{
	if( laz[rt]==0 )	return;
	mi[ls] += laz[rt], mi[rs] += laz[rt];
	laz[ls] += laz[rt], laz[rs] += laz[rt];
	laz[rt] = 0; 
}
void add(int rt,int l,int r,int L,int R,int val)
{
	if( l>R || r<L )	return;
	if( l>=L && r<=R )
	{
		mi[rt] += val; laz[rt] += val;
		return;
	}
	pushdown(rt,l,r);
	add( lson,L,R,val ); add( rson,L,R,val );
	mi[rt] = min( mi[ls],mi[rs] );
}
int solve()
{
	int r = 1, res = 1e6;
	for(int l=1;l<=n;l++)
	{
		while( mi[1]<=0 && r<=n )
			add(1,1,m,a[r].l,a[r].r,1 ),r++;
		if( mi[1]>0 )	res = min( res,a[r-1].w-a[l].w );
		add( 1,1,m,a[l].l,a[l].r,-1 );
	}
	return res;
}
signed main()
{
	scanf("%d%d",&n,&m );  m--;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w );
		a[i].r--;
	}
	sort( a+1,a+1+n );
	cout << solve();
}

以上是关于Educational Codeforces112 1555.E. Boring Segments(尺取+线段树)的主要内容,如果未能解决你的问题,请参考以下文章

Educational Codeforces Round 112 (Rated for Div. 2)-A. PizzaForces-题解

Educational Codeforces Round 112 (Rated for Div. 2)-C. Coin Rows-题解

Educational Codeforces Round 112 (Rated for Div. 2)-C. Coin Rows-题解

Educational Codeforces Round 112 (Rated for Div. 2)-B. Two Tables-题解

Educational Codeforces Round 112 (Rated for Div. 2)-B. Two Tables-题解

Educational Codeforces Round 112 (Rated for Div. 2) B. Two Tables