并不对劲的bzoj4651:loj2086:uoj222:p1712:[NOI2016]区间

题目大意

\(n\)(\(n\leq 5*10^5\))个闭区间\([L_1,R_1],[L_2,R_2],...,[L_n,R_n]\)(\(\forall i\in [1,n],0\leq L_i\leq R_i\leq 10^9\))
要选取\(m\)个区间,使这\(m\)个区间的交不为空,方案的花费为被选中的区间中 长度最长的区间的长度 减 长度最短的区间的长度
求花费最小的方案,或判断无解

题解

\(n\)个区间按区间长度排序
问题转化成对于所有满足存在一点被\([L_l,R_l],[L_{l+1},R_{l+1}],...,[L_r,R_r]\)覆盖不少于\(m\)次的\([l,r]\)中,使\(R_r-L_r-R_l+L_l\)最小
发现将合法的\([l,r]\)中的\(r\)右移时,要想产生更优的解,\(l\)也得右移,也就是单调性
那就可以从小到大枚举\(r\),维护当前最优解的\(l\)的位置,用权值线段树或离散化后用线段树判断是否有一点被覆盖超过\(m\)
但是\(n\)比较大,用权值线段树可能会被卡

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 500010
#define ls (u<<1)
#define rs (u<<1|1)
#define mi (l+r>>1)
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}
void write(int x)
{
    if(x==0){putchar('0'),putchar('\n');return;}
    int f=0;char ch[20];
    if(x<0)putchar('-'),x=-x;
    while(x)ch[++f]=x%10+'0',x/=10;
    while(f)putchar(ch[f--]);
    putchar('\n');
    return;
}
int n,ext[maxn<<1],cnte,tr[maxn<<3],mk[maxn<<3],ans=-1,m;
struct node{int l,r;}nd[maxn];
bool cmp(node x,node y){return x.r-x.l<y.r-y.l;}
void mark(int u,int k){tr[u]+=k,mk[u]+=k;}
void pd(int u){if(mk[u])mark(ls,mk[u]),mark(rs,mk[u]),mk[u]=0;}
void pu(int u){tr[u]=max(tr[ls],tr[rs]);}
void add(int u,int l,int r,int x,int y,int k)
{
    if(x<=l&&r<=y)return mark(u,k);
    pd(u);
    if(x<=mi)add(ls,l,mi,x,y,k);
    if(y>mi)add(rs,mi+1,r,x,y,k);
    return pu(u);
}
int getr(int x)
{
    int l=1,r=cnte,ans=cnte+1;
    while(l<=r)
    {
        int mid=mi;
        if(ext[mid]<x)l=mid+1;
        else if(ext[mid]>x)r=mid-1;
        else ans=min(ans,mid),r=mid-1;
    }
    return ans;
}
int jud(int i,int j)
{
    add(1,1,cnte,getr(nd[j].l),getr(nd[j].r),-1);
    int x=tr[1];
    if(x>=m)return 1;
    add(1,1,cnte,getr(nd[j].l),getr(nd[j].r),1);return 0;
}
signed main()
{
    n=read(),m=read();
    rep(i,1,n)nd[i].l=read(),nd[i].r=read(),ext[++cnte]=nd[i].l,ext[++cnte]=nd[i].r;
    sort(nd+1,nd+n+1,cmp),sort(ext+1,ext+cnte+1);int j=1;
    rep(i,1,n)
    {
        add(1,1,cnte,getr(nd[i].l),getr(nd[i].r),1);
        while(jud(i,j)&&j<=i)j++;
        if(tr[1]>=m)ans=(ans==-1)?(nd[i].r-nd[i].l-nd[j].r+nd[j].l):min(ans,(nd[i].r-nd[i].l-nd[j].r+nd[j].l));
    }
    write(ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xzyf/p/10391451.html