题解:[NOI2016]区间

传送门

在数轴上有NN 个闭区间 [l_1,r_1],[l_2,r_2],…,[l_n,r_n][l_1,r_1 ],[l_2 ,r_2 ],…,。现在要从中选出M 个区间,使得这M 个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间,都有 l_i≤x≤r_i 。
对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 的长度定义为r-l,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出-1−1 。

对于这个题目,很容易可以联想到线段树,因为他是对区间进行操作,那么每次覆盖就是对这一段区间+1,于是我们就这样加,加到最大值为m为止。
对于怎么找区间差最小,这里运用了尺取法的思想(大佬的博客),两个指针,根据排好的序进行移动。
最后,因为数据范围比较大,所以还需要离散化,我是手打的离散化,没有有STL的太多东西
完整代码如下:

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
#define ll long long
const int N=10000010;
#define re register
#define gc getchar()
#define ll long long
#define il inline
il int read() {
	re int x(0),f(1);
	re char ch=gc;
	while(ch<'0'||ch>'9') {
		if(ch=='-') f=-1;
		ch=gc;
	}
	while(ch>='0'&&ch<='9') {
		x=(x<<1)+(x<<3)+(ch^48);
		ch=gc;
	}
	return x*f;
}
int ma[N],ad[N];
namespace xds {
#define ls id<<1
#define rs id<<1|1
	void pushup(int id) {
		ma[id]=max(ma[ls],ma[rs]);
	}
	void pushdown(int id) {
		if(ad[id]) {
			ad[ls]+=ad[id];
			ad[rs]+=ad[id];
			ma[ls]+=ad[id];
			ma[rs]+=ad[id];
			ad[id]=0;
		}
	}
	void change(int id,int l,int r,int L,int R,int val) {
		if(l>=L&&r<=R) {
			ma[id]+=val;
			ad[id]+=val;
			return;
		}
		pushdown(id);
		int mid=(l+r)>>1;
		if(mid>=L) change(ls,l,mid,L,R,val);
		if(mid<R) change(rs,mid+1,r,L,R,val);
		pushup(id);
	}
}
struct node {
	int l,r,len;
} e[N];
struct Node {
	int v,id;
	bool flag;
} c[N];
int n,m,cnt,tot;
bool cmp(node a,node b) {
	return a.len==b.len?a.l<b.l:a.len<b.len;
}
bool Cmp(Node a,Node b) {
	return a.v<b.v;
}

int main() {

	n=read(),m=read();
	for(int i=1; i<=n; ++i) {
		e[i].l=read();
		e[i].r=read();
		e[i].len=e[i].r-e[i].l;
	}
	sort(e+1,e+1+n,cmp);
	for(int i=1; i<=n; ++i) {
		c[++cnt]=(Node) {
			e[i].l,i,0
		},
		c[++cnt]=(Node) {
			e[i].r,i,1
		};
	}
	sort(c+1,c+1+cnt,Cmp);
	c[0].v=-1;
	for(int i=1; i<=cnt; ++i) {
		if(c[i].v!=c[i-1].v) ++tot;
		c[i].flag?e[c[i].id].r=tot:e[c[i].id].l=tot;
	}
	
	int last=1,ans=1e9;
	for(int i=1; i<=n; ++i) {
		xds::change(1,1,tot,e[i].l,e[i].r,1);
		while(ma[1]>=m) {
			xds::change(1,1,tot,e[last].l,e[last].r,-1);
			ans=min(ans,e[i].len-e[last].len),++last;
		}
	}
	if(ans==1e9) cout<<-1;
	else cout<<ans;

	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43464026/article/details/87388327