P1712 [NOI2016]区间
题目描述
P1712 [NOI2016]区间
Solution
尺取法+线段树
一个显然的想法是按区间长度排序。
每一次多选取一个区间相当于区间覆盖次数加1,每一次少选取一个区间就有区间覆盖次数减1。
可以用线段树维护区间覆盖次数的最大值。
于是转化成了一个Two-Pointers的问题,尺取法扫一遍即可。
时间复杂度 。
Code
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=1e6+50;inline int read()
{int x=0,f=1; char c=getchar();while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f;
}
struct qnode{int opt,id,x,color; } q[MAXN];
int compareq(qnode x,qnode y) { return (x.x<y.x)||(x.x==y.x&&x.opt<y.opt); }
struct anode{int lpre,rpre,lnow,rnow,len; } a[MAXN];
int comparea(anode x,anode y){ return x.len<y.len; }
struct Segment_Tree
{struct segnode{int l,r,tag,mx; } tree[MAXN<<2];void up(int x){ tree[x].mx=max(tree[x<<1].mx,tree[x<<1|1].mx); }void down(int x){if (tree[x].tag!=0){int q=tree[x].tag;tree[x<<1].tag+=q,tree[x<<1].mx+=q;tree[x<<1|1].tag+=q,tree[x<<1|1].mx+=q;tree[x].tag=0;}}void build(int x,int l,int r){if ((tree[x].l=l)==(tree[x].r=r)) return;int mid=(l+r)>>1;build(x<<1,l,mid);build(x<<1|1,mid+1,r);}int query(int x,int l,int r){if (tree[x].l>=l&&tree[x].r<=r) return tree[x].mx;down(x);int mid=(tree[x].l+tree[x].r)>>1;if (r<=mid) return query(x<<1,l,r);else if (l>mid) return query(x<<1|1,l,r);else return max(query(x<<1,l,mid),query(x<<1|1,mid+1,r));}void change(int x,int l,int r,int y){if (tree[x].l>=l&&tree[x].r<=r){tree[x].mx+=y;tree[x].tag+=y;return;}down(x);int mid=(tree[x].l+tree[x].r)>>1;if (r<=mid) change(x<<1,l,r,y);else if (l>mid) change(x<<1|1,l,r,y);else change(x<<1,l,mid,y),change(x<<1|1,mid+1,r,y);up(x);}
} segment;
int main()
{int n=read(),m=read(),num=0;for (int i=1;i<=n;i++){int l=read(),r=read();q[++num]=(qnode){0,i,l,0};q[++num]=(qnode){1,i,r,0};}sort(q+1,q+num+1,compareq);q[0].x=-1;for (int i=1;i<=num;i++) {q[i].color=q[i-1].color+(q[i].x!=q[i-1].x);if (q[i].opt==0) a[q[i].id].lpre=q[i].x,a[q[i].id].lnow=q[i].color;if (q[i].opt==1) a[q[i].id].rpre=q[i].x,a[q[i].id].rnow=q[i].color,a[q[i].id].len=a[q[i].id].rpre-a[q[i].id].lpre+1;}sort(a+1,a+n+1,comparea);cout<<endl;for (int i=1;i<=n;i++) cout<<a[i].lpre<<" "<<a[i].rpre<<" "<<a[i].lnow<<" "<<a[i].rnow<<" "<<a[i].len<<endl;segment.build(1,1,q[num].color);int ans=INF;for (int l=1,r=1;r<=n;r++){segment.change(1,a[r].lnow,a[r].rnow,1);while (segment.query(1,1,q[num].color)>=m) {ans=min(ans,a[r].len-a[l].len);segment.change(1,a[l].lnow,a[l].rnow,-1);l++;}}if (ans==INF) puts("-1"); else printf("%d\n",ans);return 0;
}