Time:2016.08.09
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
当时打同步赛的时候
花了3h去做T3提答
大概玩了50分
回来看T1竟然是懵逼状态……
想了一会,满脑子都是离散化后差分前缀和处理blabla
但不知道怎么处理区间覆盖大于m时答案的最优性
(为什么当时连按区间大小排序的思路都没有想到?!)
其实按照区间大小排序,那么答案一定是a[l],a[l+1]..a[r]这些区间的并集,所以我们把i从1枚举到n,同时j=1,操作为
1.每次覆盖一下区间a[j],看一下有没有被覆盖大于等于m的点,如果有就去拿最长区间-最小区间与ans比较,否则++j,继续看一下有没有覆盖大于等于m的点;
2.把a[i]区间去除
覆盖,去除,检查大于等于m的点都可以用线段树的区间覆盖,单点查询最大值解决
复杂度
O(nlog2n)
常数主要在离散化那里
希望明年的自己不会滚粗
……
……
……
但前提是要先进省队!!!
……
……
……
更大的前提是把3个月后的NOIP考好!!!
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#define M 500002
using namespace std;
int in()
{
int t=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<3)+(t<<1)+ch-48,ch=getchar();
return t;
}
int a[M<<1],lazy[M<<3],tr[M<<3];
int n=in(),m=in();
struct node
{
int l,r,len;
bool operator <(node other)const {return len<other.len;}
}q[M];
void pushdown(int rt)
{
if (!lazy[rt]) return;
lazy[rt<<1]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
tr[rt<<1]+=lazy[rt];
tr[rt<<1|1]+=lazy[rt];
lazy[rt]=0;
}
void update(int rt,int begin,int end,int L,int R,int val)
{
if (L<=begin&&end<=R)
{
tr[rt]+=val;
lazy[rt]+=val;
return;
}
pushdown(rt);
int mid=begin+end>>1;
if (mid>=L) update(rt<<1,begin,mid,L,R,val);
if (mid<R) update(rt<<1|1,mid+1,end,L,R,val);
tr[rt]=max(tr[rt<<1],tr[rt<<1|1]);
}
main()
{
for (int i=1;i<=n;i++)
q[i].l=in(),
q[i].r=in(),
q[i].len=q[i].r-q[i].l,
a[++a[0]]=q[i].l,
a[++a[0]]=q[i].r;
sort(a+1,a+a[0]+1);
a[0]=unique(a+1,a+a[0]+1)-(a+1);
for (int i=1;i<=n;i++)
q[i].l=lower_bound(a+1,a+a[0]+1,q[i].l)-a,
q[i].r=lower_bound(a+1,a+a[0]+1,q[i].r)-a;
sort(q+1,q+n+1);
int ans=1<<30,t=0;
for (int i=1;i<=n;i++)
{
while (t<n&&tr[1]<m)
t++,
update(1,1,a[0],q[t].l,q[t].r,1);
if (tr[1]>=m) ans=min(ans,q[t].len-q[i].len);
else break;
update(1,1,a[0],q[i].l,q[i].r,-1);
}
printf("%d",ans==1<<30?-1:ans);
}