Luogu P1712 [NOI2016]区间

题目
很显然的想法,区间越长越有利。
我们离散化,按区间长度降序排序。
然后用尺取法,一个个的加入区间头,并且当存在某个位置被大于等于\(M\)个区间覆盖时,删掉区间尾。
我们需要支持区间加和全局最大值,直接线段树维护即可。
代码是很久以前写的了。

#include<bits/stdc++.h>
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
}
using namespace IO;
inline int min(register int a,register int b){return a<b? a:b;}
inline int max(register int a,register int b){return a>b? a:b;}
const int N=500001;
struct node{int l,r,w;}a[N];
inline bool operator<(node a,node b){return a.w<b.w;}
int Hash[N<<1],tag[N<<3],sum[N<<3];
#define lson (p<<1)
#define rson (p<<1|1)
#define mid ((l+r)>>1)
#define same L,R,k
#define left lson,l,mid,same
#define right rson,mid+1,r,same
inline void Pushdown(register int p){if(tag[p])sum[lson]+=tag[p],sum[rson]+=tag[p],tag[lson]+=tag[p],tag[rson]+=tag[p],tag[p]=0;}
inline void Pushup(register int p){sum[p]=max(sum[lson],sum[rson]);}
void Update(int p,int l,int r,int L,int R,int k)
{
    if(L>r||l>R) return;
    if(L<=l&&r<=R) return (void)(tag[p]+=k,sum[p]+=k);
    Pushdown(p),Update(left),Update(right),Pushup(p);
}
int main()
{
    register int n=read(),m=read(),num,Min=2147483647,Max=0,head=0,tail=0,ans=2147483647;
    for(register int i=1,tot=0;i<=n;++i) Hash[++tot]=a[i].l=read(),Hash[++tot]=a[i].r=read(),a[i].w=a[i].r-a[i].l;
    sort(Hash+1,Hash+(n<<1)+1),num=unique(Hash+1,Hash+(n<<1)+1)-(Hash+1),sort(a+1,a+n+1);
    for(register int i=1;i<=n;++i) Min=min(Min,a[i].l=lower_bound(Hash+1,Hash+num+1,a[i].l)-Hash),Max=max(Max,a[i].r=lower_bound(Hash+1,Hash+num+1,a[i].r)-Hash);
    while(tail<n)
    {
    while(sum[1]<m&&tail<=n) ++tail,Update(1,Min,Max,a[tail].l,a[tail].r,1);
    if(sum[1]<m) break;
    while(sum[1]>=m&&tail>=head) ++head,Update(1,Min,Max,a[head].l,a[head].r,-1);
    ans=min(ans,a[tail].w-a[head].w);
    }
    if(ans==2147483647) ans=-1;
    return cout<<ans,0;
}

转载于:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11543287.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值