bzoj4653: [Noi2016]区间

Posted AKCqhzdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4653: [Noi2016]区间相关的知识,希望对你有一定的参考价值。

嗯这道题又涨姿势了。第一次看见这样的离散化。。666

说说做法吧,第一眼就看出线段树的说,贪心没看出来。。就只能膜网上的题解了,我们先将长度给排序一下,然后看看从当前位置(L)开始,要到哪个点(R)就可以达到m个区间共同包含至少一个位置,这就是一种解,判断m个区间的方式就是利用线段树维护一个区间最大值。对于那些没有贡献的区间,插入也不影响操作,因为L~R之间的不是最值,对答案没有影响。

#include<set>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m;
struct Seg
{
    int l,r,lc,rc,c,u;
}tr[2100000];int trlen;
void bt(int l,int r)
{
    trlen++;int now=trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].c=0;tr[now].u=0;
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
void inherit(int now,int k)
{
    tr[now].c+=k;tr[now].u+=k;
}
void change(int now,int l,int r,int k)
{
    if(tr[now].l==l&&tr[now].r==r){inherit(now,k);return ;}
    
    int lc=tr[now].lc,rc=tr[now].rc;
    if(tr[now].u!=0)
    {
        inherit(lc,tr[now].u);
        inherit(rc,tr[now].u);
        tr[now].u=0;
    }
    
    int mid=(tr[now].l+tr[now].r)/2;
         if(r<=mid)  change(lc,l,r,k);
    else if(mid+1<=l)change(rc,l,r,k);
    else
    {
        change(lc,l,mid,k);
        change(rc,mid+1,r,k);
    }
    tr[now].c=max(tr[lc].c,tr[rc].c);
}
struct lr
{
    int l,r,s;
}a[510000],b[510000];
int lslen,ls[1100000];
bool cmp(lr n1,lr n2)
{
    if(n1.s<n2.s||(n1.s==n2.s&&n1.l<=n2.l))return true;
    return false;
}
void LSH()
{
    lslen=0;
    for(int i=1;i<=n;i++)
    {
        ls[++lslen]=a[i].l;
        ls[++lslen]=a[i].r;
    }
    sort(ls+1,ls+1+lslen);
    lslen=unique(ls+1,ls+1+lslen)-ls-1;
    for(int i=1;i<=n;i++)
    {
        b[i].l=lower_bound(ls+1,ls+lslen+1,a[i].l)-ls;
        b[i].r=lower_bound(ls+1,ls+lslen+1,a[i].r)-ls;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i].l,&a[i].r);
        a[i].s=a[i].r-a[i].l;
    }
    sort(a+1,a+1+n,cmp);
    LSH();
    trlen=0;bt(1,lslen);
    int L=1,R=0,ans=2147483647;
    while(L<=n)
    {
        while(R<n&&tr[1].c<m)
        {
            R++;
            change(1,b[R].l,b[R].r,1);
        }
        if(tr[1].c>=m)ans=min(ans,a[R].s-a[L].s);
        change(1,b[L].l,b[L].r,-1);L++;
    }
    if(ans==2147483647)printf("-1\n");
    else printf("%d\n",ans);
    return 0;
}

 

以上是关于bzoj4653: [Noi2016]区间的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ4653][Noi2016]区间

bzoj 4653: [Noi2016]区间

BZOJ4653: [Noi2016]区间

bzoj4653 [Noi2016]区间

BZOJ4653[Noi2016]区间 双指针法+线段树

[BZOJ]4653: [Noi2016]区间