P1712 [NOI2016]区间 题解

37 篇文章 0 订阅

题目

线段树 + 双指针

首先,将区间的端点离散化,并且将区间按长度排序,使得我们连续选的若干个区间最长与最短的长度相差最小

接着,我们用双指针寻找长度为 m m m 的区间集合( m m m 个区间),当区间被选中时,将它所覆盖的地方区间加一,取消选中时减一。如果有任意一个位置被覆盖了 x x x 次,说明这是有 x x x 个区间公共点;每次询问所有位置被标记次数的最大值 m a x v maxv maxv,如果 m a x v = m maxv=m maxv=m 则更新答案

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
const long long Maxn=500000+100,inf=(1ll<<60);
const long long Maxm=Maxn<<3;
long long maxv[Maxm],add[Maxm];
long long c[Maxm];
long long n,m,tot,ans=inf;
map <long long , long long> id;
struct node{
	long long l,r,len;
}a[Maxn];
inline bool cmp(node x,node y)
{
	return x.len<y.len;
}
inline long long read()
{
	long long s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return s*w;
}
inline void push_up(long long k)
{
	maxv[k]=max(maxv[k<<1],maxv[k<<1|1]);
}
inline void upd(long long k,long long v)
{
	add[k]+=v;
	maxv[k]+=v;
}
inline void push_down(long long k)
{
	if(!add[k])return;
	upd(k<<1,add[k]);
	upd(k<<1|1,add[k]);
	add[k]=0;
}
void modify(long long k,long long l,long long r,long long x,long long y,long long v)
{
	if(x<=l && r<=y)return upd(k,v);
	push_down(k);
	long long mid=(l+r)>>1;
	if(x<=mid)modify(k<<1,l,mid,x,y,v);
	if(mid<y)modify(k<<1|1,mid+1,r,x,y,v);
	push_up(k);
}
long long query(long long k,long long l,long long r,long long x,long long y)
{
	if(x<=l && r<=y)return maxv[k];
	push_down(k);
	long long mid=(l+r)>>1,ret=0;
	if(x<=mid)ret=query(k<<1,l,mid,x,y);
	if(mid<y)ret=max(ret,query(k<<1|1,mid+1,r,x,y));
	return ret;
}
int main()
{
//	freopen("in.txt","r",stdin);
	n=read(),m=read();
	for(long long i=1;i<=n;++i)
	{
		a[i].l=read(),a[i].r=read();
		a[i].len=a[i].r-a[i].l;
		c[++tot]=a[i].l,c[++tot]=a[i].r;
	}
	sort(c+1,c+1+tot);
	tot=0;
	for(long long i=1;i<=(n<<1);++i)
	if(!id[c[i]])id[c[i]]=++tot;
	
	for(long long i=1;i<=n;++i)
	{
		a[i].l=id[a[i].l];
		a[i].r=id[a[i].r];
	}
	sort(a+1,a+1+n,cmp);
	long long l=1,r=0;
	while(r<n)
	{
		while(r<n && maxv[1]<m)
		{
			++r;
			modify(1,1,tot,a[r].l,a[r].r,1);
		}
		if(maxv[1]<m)continue;
		while(l<=r && maxv[1]>=m)
		{
			ans=min(ans,a[r].len-a[l].len);
			modify(1,1,tot,a[l].l,a[l].r,-1);
			++l;
		}
	}
	if(ans==inf)puts("-1");
	else printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值