并不对劲的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;
}