洛谷$P1712\ [NOI2016]$区间 线段树

正解:线段树

解题报告:

传送门$QwQ$

$umm$很久以前做的了来补个题解$QwQ$

考虑给每个区间按权值($r-l$从大往小排序,依次加入,然后考虑如果有一个位置被覆盖次数等于$m$了就可以把权值最大的那个删去直到被覆盖次数小于$m$,顺便更新答案

然后就做完辣!$QwQ$

放下代码趴,然后因为是去年的代码了所以码风可能有点丑,,,懒得改了$QwQ$

$over$

#include 
#include 
#include 
using namespace std;
int n,m,b[2000009],c[2000009],d[1000009],mx[4000009],add[4000009],l=1,r=0,ans=0x7fffffff,num;
struct seg
{
    int x,y,len;
    inline bool operator <(const seg& rhs) const
    {
        return len>rhs.len;
    }
}a[500009];
inline int read()
{
    char ch=getchar();int x=0;
    while(ch>'9' || ch<'0')ch=getchar();
    while(ch<='9' && ch>='0')x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
    return x;
}
inline void ins(int l,int r,int x,int y,int k,int v)
{
    if (x<=l&&y>=r)
    {
        add[k]+=v;
        mx[k]+=v;
        return;
    }
    int mid=l+r>>1;
    if (x<=mid) ins(l,mid,x,y,k<<1,v);
    if (y>mid) ins(mid+1,r,x,y,k<<1|1,v);
    mx[k]=max(mx[k<<1],mx[k<<1|1]);
    mx[k]+=add[k];
}
int low(int x)
{
    int l=1,r=num,mid;
    while (l<r)
    {
        mid=(l+r)>>1;
        if (b[mid]>=x) r=mid;
        else l=mid+1;
    }
    return l;
}
int main()
{
    n=read(),m=read();
    num=0;
    for (int i=1;i<=n;i++)
    {
        a[i].x=read();
        a[i].y=read();
        a[i].len=a[i].y-a[i].x;
        b[++num]=a[i].x;
        b[++num]=a[i].y;
    }
    sort(a+1,a+n+1);
    sort(b+1,b+num+1);
    for (int i=1;i<=n;i++) a[i].x=low(a[i].x),a[i].y=low(a[i].y);
    for (int r=1;r<=n;r++)
    {
        ins(1,num,a[r].x,a[r].y,1,1);
        while (mx[1]>=m)
        {
            ans=min(ans,a[l].len-a[r].len);
            ins(1,num,a[l].x,a[l].y,1,-1);
            l++;
        }
    }
    if (ans!=0x7fffffff) printf("%d\n",ans); 
    else printf("-1");
    return 0;
}
View Code

你可能感兴趣的:(洛谷$P1712\ [NOI2016]$区间 线段树)