P1712 [NOI2016] 区间 尺取法 线段树

题意:

戳这里

分析:

这个题目的限制条件只有两个:

  1. 选出 (m) 个相交的区间
  2. 求最大跟最小的差值

我的第一反应是,按处理出每一个线段存在的范围,枚举交点,这样就满足了第一个条件,但是我发现这个第二个条件没法做呀,貌似没有什么数据结构能支持动态查询排名相差为 (m) 的两个数的差值的最小值,所以这个思路可以扔了

我们发现其实限制更大的是第二个条件,所以我们考虑在满足第二个条件的前提下,尽量去满足第一个条件,那么我们按照区间的长度升序排序,双指针扫一遍,每当存在一个点被不小于 (m) 个区间覆盖之后,用双指针的右端点的长度减去左端点的长度,然后左端点++,这样在排序满足第二个条件,然后用一个数据结构维护区间最值满足第一个条件,直接上线段树就好了

代码:

#include<bits/stdc++.h>
#define inl inline
#define reg register
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define fir first
#define sec second

using namespace std;

namespace zzc
{
    typedef long long ll;
    inl ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const ll maxn = 1e6+5;
    ll n,m,ans=0x3f3f3f3f3f3f3f3f,cnt;
    ll val[maxn<<2],tag[maxn<<2],a[maxn],b[maxn],c[maxn<<1];
    pair<ll,pair<ll,ll> > p[maxn];
    
    inl void pushup(ll rt)
    {
        val[rt]=max(val[lc],val[rc]);
    }

    inl void pushdown(ll rt)
    {
        if(tag[rt])
        {
            val[lc]+=tag[rt];tag[lc]+=tag[rt];
            val[rc]+=tag[rt];tag[rc]+=tag[rt];
            tag[rt]=0;
        }
    }

    void modify(ll rt,ll l,ll r,ll ql,ll qr,ll k)
    {
        if(ql<=l&&r<=qr)
        {
            val[rt]+=k;
            tag[rt]+=k;
            return ;
        }
        ll mid=(l+r)>>1;
        pushdown(rt);
        if(ql<=mid) modify(lc,l,mid,ql,qr,k);
        if(qr>mid) modify(rc,mid+1,r,ql,qr,k);
        pushup(rt);
    }

    void work()
    {
        n=read();m=read();
        for(reg ll i=1;i<=n;i++)
        {
            a[i]=read();c[++cnt]=a[i];
            b[i]=read();c[++cnt]=b[i];
        }
        sort(c+1,c+cnt+1);
        cnt=unique(c+1,c+cnt+1)-c-1;
        for(reg ll i=1;i<=n;i++)
        {
            ll len=b[i]-a[i]+1;
            b[i]=lower_bound(c+1,c+cnt+1,b[i])-c;
            a[i]=lower_bound(c+1,c+cnt+1,a[i])-c;
            p[i]=mk(len,mk(a[i],b[i]));
        }
        sort(p+1,p+n+1);
        for(reg ll i=1,j=1;i<=n;i++)
        {
            modify(1,1,cnt,p[i].sec.fir,p[i].sec.sec,1);
            while(val[1]>=m)
            {
                ans=min(ans,p[i].fir-p[j].fir);
                modify(1,1,cnt,p[j].sec.fir,p[j].sec.sec,-1);
                j++;
            }
        }
        if(ans==0x3f3f3f3f3f3f3f3f) puts("-1");
        else printf("%lld
",ans);
    }


}

int main()
{
    zzc::work();
    return 0;
}
原文地址:https://www.cnblogs.com/youth518/p/14384080.html