zoukankan      html  css  js  c++  java
  • BZOJ4411

    Portal

    Description

    给出平面上的(n(nleq10^5))个整点。画两条直线(x=x_0)(y=y_0)将这些点划分成(s_1,s_2,s_3,s_4)个点,最小化(max{s_1,s_2,s_3,s_4})

    Solution

    二分答案+线段树。
    首先进行离散化,记录(sumY[i])表示(yleq i)的点的个数。
    检查(m)是否合法时,枚举(x_0)并查找是否存在合法的(y_0)。将↖称为(s_1),↙称为(s_2),↗称为(s_3),↘称为(s_4)。那么我们找到使得(s_1,s_2leq m)的最大的(y_0),然后检查(s_3,s_4)是否不超过(m)。我们将(xleq x_0)的点加入线段树,在线段树上二分来找到最大的(y_0)使得线段树上([1,y_0])中的点数和(即(s_1))不超过(m)(s_2=sumY[y_0]-s_1)也不超过(m)。找到(y_0)后检查(s_3=sum[rt]-s_1,s_4=n-s_1-s_2-s_3)是否均不超过(m),若均合法则说明(ansleq m),否则继续枚举(x_0)。若对于所有(x_0)均不存在合法的(y_0),则说明(ans>m)

    时间复杂度(O(nlog^2n))

    Code

    //[Usaco2016 Feb]Load balancing
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    inline char gc()
    {
        static char now[1<<16],*s,*t;
        if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
        return *s++;
    }
    inline int read()
    {
        int x=0; char ch=gc();
        while(ch<'0'||'9'<ch) ch=gc();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x;
    }
    const int N=1e5+10;
    int n,nX,nY; int sumY[N];
    struct point{int x,y;} pt[N];
    bool cmpX(point x,point y) {return x.x<y.x;}
    int mapX[N],mapY[N];
    void discrete()
    {
        for(int i=1;i<=n;i++) mapX[i]=pt[i].x,mapY[i]=pt[i].y;
        sort(mapX+1,mapX+n+1); nX=unique(mapX+1,mapX+n+1)-mapX-1;
        for(int i=1;i<=n;i++) pt[i].x=lower_bound(mapX+1,mapX+nX+1,pt[i].x)-mapX;
        sort(mapY+1,mapY+n+1); nY=unique(mapY+1,mapY+n+1)-mapY-1;
        for(int i=1;i<=n;i++) pt[i].y=lower_bound(mapY+1,mapY+nY+1,pt[i].y)-mapY;
        sort(pt+1,pt+n+1,cmpX);
    }
    const int Ns=4e5+10;
    #define Ls (p<<1)
    #define Rs (p<<1|1)
    int rt,sum[Ns]; int clr[Ns];
    int optL,optR;
    void update(int p) {sum[p]=sum[Ls]+sum[Rs];}
    void pushdw(int p) {if(clr[p]) sum[Ls]=sum[Rs]=0,clr[Ls]=clr[Rs]=true,clr[p]=false;}
    void ins(int p,int L0,int R0,int x,int v)
    {
        if(L0==R0) {sum[p]+=v; return;}
        pushdw(p);
        int mid=L0+R0>>1;
        if(x<=mid) ins(Ls,L0,mid,x,v);
        else ins(Rs,mid+1,R0,x,v);
        update(p);
    }
    int query1(int p,int L0,int R0,int s1,int x)
    {
        if(L0==R0) return L0;
        pushdw(p);
        int mid=L0+R0>>1; int t1=s1+sum[Ls],t2=sumY[mid]-t1;
        if(x<t1||x<t2) return query1(Ls,L0,mid,s1,x);
        else return query1(Rs,mid+1,R0,t1,x);
    }
    int query2(int p,int L0,int R0)
    {
        if(optL<=L0&&R0<=optR) return sum[p];
        pushdw(p);
        int mid=L0+R0>>1; int res=0;
        if(optL<=mid) res+=query2(Ls,L0,mid);
        if(mid<optR) res+=query2(Rs,mid+1,R0);
        return res;
    }
    bool check(int m)
    {
        rt=1; sum[rt]=0,clr[rt]=true;
        for(int i=1,t=1;i<=nX;i++)
        {
            while(pt[t].x==i) ins(rt,1,nY,pt[t].y,1),t++;
            if(sum[rt]>m+m) break;
            else if(n-sum[rt]>m+m) continue;
            int j=query1(rt,1,nY,0,m)-1;
            optL=1,optR=j; int s1=query2(rt,1,nY);
            int s2=sumY[j]-s1,s3=sum[rt]-s1,s4=n-s1-s2-s3;
            if(s1>m||s2>m) printf("query1 GG
    ");
            if(s3<=m&&s4<=m) return true; 
        }
        return false;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) pt[i].x=read(),pt[i].y=read();
        discrete();
        for(int i=1;i<=n;i++) sumY[pt[i].y]++;
        for(int i=1;i<=nY;i++) sumY[i]+=sumY[i-1];
        int L=n/4-1,R=n;
        while(L<=R)
        {
            int mid=L+R>>1;
            if(check(mid)) R=mid-1;
            else L=mid+1;
        }
        printf("%d
    ",L);
        return 0;
    }
    

    P.S.

    sro Icefox的(O(nlogn))做法 orz,比我强多啦

  • 相关阅读:
    基于Metaweblog API 接口一键发布到国内外主流博客平台
    uva144 Student Grants
    Uva 10452
    Uva 439 Knight Moves
    Uva 352 The Seasonal War
    switch语句
    java——基础知识
    我的lua学习2
    codeforces 431 D. Random Task 组合数学
    codeforces 285 D. Permutation Sum 状压 dfs打表
  • 原文地址:https://www.cnblogs.com/VisJiao/p/BZOJ4411.html
Copyright © 2011-2022 走看看