P1712 [NOI2016]区间
思路
对于这道题,要求求出的相当于是一个方案使得某个点的覆盖次数>=m
然后可以使用类似two-pointer的写法,按长度排序之后,对每个r,求出答案之后取min
因为删掉r之后,如果存在解,答案不会变的更劣,如果不存在,则需要继续加入,得到的第一个合法解一定是对于当前的r最优的解
然后如果插入了多于m个区间其实没有关系,因为答案只和最长区间长度-最短区间长度有关系
要使用离散化,只动态开点会MLE
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int ans=0x3f3f3f3f,rx,lx,n,m,Nodecnt,root,num[1000100],numcnt;
struct Node{
int lson,rson,maxx,add;
}Seg[500000*30];
struct interval{
int l,r;
bool operator < (const interval &b) const{
return (r-l)<(b.r-b.l);
}
}I[501000];
void pushup(int o){
Seg[o].maxx=max(Seg[Seg[o].lson].maxx,Seg[Seg[o].rson].maxx);
}
void pushdown(int o){
if(Seg[o].add){
if(!Seg[o].lson)
Seg[o].lson=++Nodecnt;
if(!Seg[o].rson)
Seg[o].rson=++Nodecnt;
Seg[Seg[o].lson].add+=Seg[o].add;
Seg[Seg[o].rson].add+=Seg[o].add;
Seg[Seg[o].lson].maxx+=Seg[o].add;
Seg[Seg[o].rson].maxx+=Seg[o].add;
Seg[o].add=0;
}
}
void add(int L,int R,int l,int r,int &o,int c){
if(!o)
o=++Nodecnt;
if(L<=num[l]&&num[r]<=R){
Seg[o].maxx+=c;
Seg[o].add+=c;
return;
}
pushdown(o);
int mid=(l+r)>>1;
if(L<=num[mid])
add(L,R,l,mid,Seg[o].lson,c);
if(R>num[mid])
add(L,R,mid+1,r,Seg[o].rson,c);
pushup(o);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d %d",&I[i].l,&I[i].r);
num[++numcnt]=I[i].l;
num[++numcnt]=I[i].r;
}
sort(I+1,I+n+1);
sort(num+1,num+numcnt+1);
numcnt=unique(num+1,num+numcnt+1)-(num+1);
// for(int i=1;i<=n;i++){
// printf("!%d %d\n",I[i].l,I[i].r);
// }
lx=n+1,rx=n;
while(rx>=m&&lx>=1){
while(lx>0&&(rx-lx+1<m||Seg[root].maxx<m)){
lx--;
if(lx==0)
break;
add(I[lx].l,I[lx].r,1,numcnt,root,1);
}
if(lx==0)
break;
// printf("[%d,%d]\n",lx,rx);
ans=min(ans,(I[rx].r-I[rx].l)-(I[lx].r-I[lx].l));
add(I[rx].l,I[rx].r,1,numcnt,root,-1);
rx--;
}
if(ans==0x3f3f3f3f)
printf("-1\n");
else
printf("%d\n",ans);
return 0;
}