1. 程式人生 > >BZOJ.4653.[NOI2016]區間(線段樹)

BZOJ.4653.[NOI2016]區間(線段樹)

zoj pri 新建 n) getchar() while pan oot problem

BZOJ4653
UOJ222

考慮二分。那麽我們可以按區間長度從小到大枚舉每個區間,對每個區間可以得到一個可用區間長度範圍。
我們要求是否存在一個點被這些區間覆蓋至少\(m\)次。這可以用線段樹區間加、求max維護(或者在線段樹上二分)。
但這是兩個\(\log\)的。

我們不二分,按長度枚舉每個區間。這樣邊枚舉邊判一下是否有點被覆蓋\(m\)次就好了。
復雜度\(O(n\log n)\)

動態開點值域線段樹MLE 95分啊QAQ。。(必然了)
另外動態開點的區間修改,下傳標記的時候要先判有沒有兒子(沒有要新建節點)。
因為這個浪費2h還算值吧。。

//42136kb   8316ms
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=5e5+5;

int ref[N<<1];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Interval
{
    int l,r,len;
    Interval() {}
    Interval(int l,int r):l(l),r(r) {len=r-l;}
    bool operator <(const Interval &x)const
    {
        return len<x.len;
    }
}A[N];
struct Segment_Tree
{
    #define S N<<3
    #define ls rt<<1
    #define rs rt<<1|1
    #define lson ls,l,m
    #define rson rs,m+1,r
    int tot,mx[S],tag[S];
    #undef S

    #define Update(x) mx[x]=std::max(mx[ls],mx[rs])
    #define Upd(x,v) tag[x]+=v,mx[x]+=v
    inline void PushDown(int rt)
    {
        Upd(ls,tag[rt]), Upd(rs,tag[rt]), tag[rt]=0;
    }
    void Modify(int rt,int l,int r,int L,int R,int val)
    {
        if(L<=l && r<=R) {Upd(rt,val); return;}
        if(tag[rt]) PushDown(rt);
        int m=l+r>>1;
        if(L<=m) Modify(lson,L,R,val);
        if(m<R) Modify(rson,L,R,val);
        Update(rt);
    }
}T;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline int Find(int x,int r)
{
    int l=1,mid;
    while(l<r)
        if(ref[mid=l+r>>1]<x) l=mid+1;
        else r=mid;
    return l;
}

int main()
{
    #define S 1,1,cnt

    int n=read(),m=read(),t=0;
    for(int i=1; i<=n; ++i) ref[++t]=read(),A[i]=Interval(ref[t-1],ref[++t]=read());
    std::sort(A+1,A+1+n);

    std::sort(ref+1,ref+1+t); int cnt=1;
    for(int i=2; i<=t; ++i) if(ref[i]!=ref[i-1]) ref[++cnt]=ref[i];
    for(int i=1; i<=n; ++i) A[i].l=Find(A[i].l,cnt), A[i].r=Find(A[i].r,cnt);

    int ans=2e9;
    for(int l=1,r=1; r<=n; ++r)
    {
        while(T.mx[1]<m && r<=n) T.Modify(S,A[r].l,A[r].r,1), ++r;
        --r;
        if(T.mx[1]>=m)
        {
            while(T.mx[1]>=m) T.Modify(S,A[l].l,A[l].r,-1), ++l;
            ans=std::min(ans,A[r].len-A[l-1].len);
        }
        else break;
    }
    printf("%d\n",ans==2e9?-1:ans);

    return 0;
}

動態開點:

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=5e5+5;

char IN[MAXIN],*SS=IN,*TT=IN;
struct Interval
{
    int l,r,len;
    Interval() {}
    Interval(int l,int r):l(l),r(r) {len=r-l;}
    bool operator <(const Interval &x)const
    {
        return len<x.len;
    }
}A[N];
struct Segment_Tree
{
    #define S N*32
    #define ls son[x][0]
    #define rs son[x][1]
    #define lson ls,l,m
    #define rson rs,m+1,r
    int tot,son[S][2],mx[S],tag[S];
    #undef S

    #define Update(x) mx[x]=std::max(mx[ls],mx[rs])
    #define Upd(x,v) tag[x]+=v,mx[x]+=v
    inline void PushDown(int x)
    {
        if(!ls) ls=++tot; Upd(ls,tag[x]);
        if(!rs) rs=++tot; Upd(rs,tag[x]);
        tag[x]=0;
    }
    void Modify(int &x,int l,int r,int L,int R,int val)
    {
        if(!x) x=++tot;
        if(L<=l && r<=R) {mx[x]+=val,tag[x]+=val; return;}
        if(tag[x]) PushDown(x);
        int m=l+r>>1;
        if(L<=m) Modify(lson,L,R,val);
        if(m<R) Modify(rson,L,R,val);
        Update(x);
    }
}T;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}

int main()
{
    #define S root,0,1000000000

    int n=read(),m=read(),root=0;
    for(int i=1,tmp; i<=n; ++i) tmp=read(),A[i]=Interval(tmp,read());
    std::sort(A+1,A+1+n);

    int ans=2e9;
    for(int l=1,r=1; r<=n; ++r)
    {
        while(T.mx[root]<m && r<=n) T.Modify(S,A[r].l,A[r].r,1), ++r;
        --r;
        if(T.mx[root]>=m)
        {
            while(T.mx[root]>=m) T.Modify(S,A[l].l,A[l].r,-1), ++l;
            ans=std::min(ans,A[r].len-A[l-1].len);
        }
        else break;
    }
    printf("%d\n",ans==2e9?-1:ans);

    return 0;
}

BZOJ.4653.[NOI2016]區間(線段樹)