先离散化
然后按照长度从小到大排序
然后按长度顺序依次加入
用线段树维护当前的覆盖最多几条
然后如果当前有点的覆盖数等于
m
的就一直出队列,直到小于
单调性可以证明,手画画搞搞也许可以吧。。。
年代太久远发现自己的代码都看不大懂了。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define g getchar()
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
inline ll read(){
ll x=0,f=1;char ch=g;
for(;ch<'0'||ch>'9';ch=g)if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=g)x=x*10+ch-'0';
return x*f;
}
inline void out(ll x){
int a[25],t=0;
if(x<0)putchar('-'),x=-x;
for(;x;x/=10)a[++t]=x%10;
for(int i=t;i;--i)putchar('0'+a[i]);
if(t==0)putchar('0');
putchar('\n');
}
struct re{int num,id;}a[4000005];
struct re2{int l,r,len;}b[4000005];
int cnt[4000005],m,fl,lll,n,now,hash[4000005],tou,ans,sum[4000005];
bool pd[4000005];
void ins(int k,int l,int r,int x,int y){
if(l==x&&y==r){++cnt[k];++sum[k];return;}
int mid=(l+r)>>1;
if(x<=mid)ins(k<<1,l,mid,x,min(mid,y));
if(y>mid)ins(k<<1|1,mid+1,r,max(mid+1,x),y);
cnt[k]=max(cnt[k<<1],cnt[k<<1|1])+sum[k];
}
int query(int k,int l,int r,int x,int y){
if(l==x&&r==y)return cnt[k];
int mid=(l+r)>>1,ans=-inf;
if(x<=mid)ans=query(k<<1,l,mid,x,min(y,mid));
if(y>mid)ans=max(ans,query(k<<1|1,mid+1,r,max(x,mid+1),y));
return ans;
}
void del(int k,int l,int r,int x,int y){
if(l==x&&y==r){--cnt[k];--sum[k];return;}
int mid=(l+r)>>1;
if(x<=mid)del(k<<1,l,mid,x,min(mid,y));
if(y>mid)del(k<<1|1,mid+1,r,max(x,mid+1),y);
cnt[k]=max(cnt[k<<1],cnt[k<<1|1])+sum[k];
}
inline bool cmp1(re x,re y){return x.num==y.num?x.id<y.id:x.num<y.num;}
inline bool cmp2(re2 x,re2 y){return x.len<y.len;}
inline int cal(int i,int j){return hash[b[j].r]-hash[b[j].l]-hash[b[i].r]+hash[b[i].l];}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i){
int x=read(),y=read();
a[i*2-1]=(re){x,i};a[i*2]=(re){y,i};
b[i]=(re2){x,y,y-x};
}
sort(a+1,a+1+n*2,cmp1);
now=1;
hash[1]=a[1].num;
for(int i=1;i<=2*n;++i){
if(a[i].num!=hash[now]){
hash[++now]=a[i].num;
if(!pd[a[i].id])
b[a[i].id].l=now,pd[a[i].id]=1;
else b[a[i].id].r=now;
}else if(!pd[a[i].id])b[a[i].id].l=now,pd[a[i].id]=1;else b[a[i].id].r=now;
}//没记错的话,到这里是离散化
ans=inf;
sort(b+1,b+1+n,cmp2);tou=1;
for(int i=0;i<n||cnt[1]==m&&i==n;){
for(;cnt[1]<m&&i<n;)++i,ins(1,1,now,b[i].l,b[i].r);
for(;cnt[1]==m&&i<=n;)
ans=min(ans,cal(tou,i)),del(1,1,now,b[tou].l,b[tou].r),++tou;
}
//cnt是线段树的统计数组,cnt1即为根,因为维护了最大值,查询复杂度O(1)
out(ans<inf?ans:-1);
return 0;
}
upd:
今儿又打了一遍
迷之优化一发艹到
rank3
。。
rank4
也是我嘿嘿嘿
好像是把画蛇添足的哈希去掉了直接预处理求出区间长度
长度也减到了66行
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define g getchar()
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,n) for(int i=1;i<=n;++i)
#define fi(i,j,k) for(int i=j;i<=k;++i)
#define di(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
inline ll read(){
ll x=0,f=1;char ch=g;
for(;ch<'0'||ch>'9';ch=g)if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=g)x=x*10+ch-'0';
return x*f;
}
inline void out(ll x){
int a[25],wei=0;
if(x<0)putchar('-'),x=-x;
for(;x;x/=10)a[++wei]=x%10;
if(wei==0){puts("0");return;}
for(int j=wei;j>=1;--j)putchar('0'+a[j]);
putchar('\n');
}
struct tr{int sum,mx;}t[2500005];
struct re{int l,r,len;}a[500005];
struct re2{int id,p;}b[1000005];
int n,m,cnt,now,np,ans,ansl;
bool pd[500005];
bool cmp1(re2 x,re2 y){return x.p<y.p;}
bool cmp2(re x,re y){return x.len>y.len;}
void ins(int k,int x,int y,int l,int r,int opt){
if(x==l&&y==r){t[k].mx+=opt;t[k].sum+=opt;return;}
int mid=(l+r)>>1;
if(x<=mid)ins(k<<1,x,min(mid,y),l,mid,opt);
if(y>mid)ins(k<<1|1,max(mid+1,x),y,mid+1,r,opt);
t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx)+t[k].sum;
}
int main(){
n=read();m=read();
rep(i,n){
a[i].l=read(),a[i].r=read();a[i].len=a[i].r-a[i].l;
b[++cnt]=(re2){i,a[i].l};b[++cnt]=(re2){i,a[i].r};
}
sort(b+1,b+1+cnt,cmp1);
for(int i=1;i<=cnt;){
++now;np=b[i].p;
for(;b[i].p==np&&i<=cnt;++i){
if(pd[b[i].id])a[b[i].id].r=now;
else pd[b[i].id]=1,a[b[i].id].l=now;
}
}
sort(a+1,a+1+n,cmp2);
ans=inf;
for(int tou=1,wei=1;wei>=tou&&wei<=n;++wei){
ins(1,a[wei].l,a[wei].r,1,now,1);
ansl=-1;
for(;t[1].mx>=m;++tou){
ansl=tou;
ins(1,a[tou].l,a[tou].r,1,now,-1);
}
if(ansl!=-1)ans=min(a[ansl].len-a[wei].len,ans);
}
out(ans==inf?-1:ans);
return 0;
}