【BZOJ4653】区间,离散化+线段树

来源:互联网 发布:日单淘宝店 编辑:程序博客网 时间:2024/05/04 05:32

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 500002using 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);}
0 0