B Load Balancing(Platinum)

前言

  • 赛时发现此题没有太多AC,就先放着了,事后发现这的确是一道好题

分析

  • 画个图了解一下题意
    图片说明
    设M为这四个区域中点数的最大数量,求一个划分方案是的M最小
  • 正经东西:
    图片说明
    那么M=max(a,b,c,d),如何求到每一个格子中点的数量呢?首先考虑简单一点的——如何维护一个范围内点的数量。这样肯定能用离散+树状数组维护。假设我们将坐标 y 离散,这个树状数组(1号)维护的是纵坐标小于等于 y 的点的数量,那么当前我们知道的即是 c + d ,a + b 。 但是不够啊,我得知道单个的QwQ,不然没法儿算。于是就来了一个方法——枚举横坐标x,将横坐标小于等于 x 的点加入到另一个树状数组(2号)中去 这样的话,就可以直接求得 c , a 的值,至于 b , d怎么求就不用说了。
  • 大致过程:离散纵坐标,把点加入到一号树状数组,枚举横坐标 x ,把横坐标小于等于 x 的点加入到二号树状数组,在纵坐标上面进行三分,求得最小的M,

代码

#include<bits/stdc++.h>

using namespace std;

const int N=1e5+10;

int n,cnt,ans;
int p[N],k[N],b[N];
//0,1
struct nkl
{
    int l,r;
}s[N];

inline bool god(nkl xx,nkl yy)
{
    return xx.l<yy.l;
}

inline int lowbit(int x)
{
    return x&(-x);
}

inline void add(int x,int id)
{
    while(x<=cnt)
    {
        if(id==1) ++k[x];
        else ++p[x];
        x+=lowbit(x);
    }
}

inline int find(int x,int id)
{
    int res=0;
    while(x)
    {
        if(id==1) res+=k[x];
        else res+=p[x];
        x-=lowbit(x);
    }
    return res;
}

inline int sum(int x,int tot)
{
    int xx=find(x,0);//左下 
    int yy=tot-xx;//左上 
    int ano=find(x,1)-xx;//右下
    return max(xx,max(yy,max(ano,n-xx-yy-ano)));    
}

inline int get(int tot)
{
    int l=1,r=cnt,res=1e9;
    while(l+1<r)
    {
        int lm=l+(r-l)/3,rm=r-(r-l)/3;
        int xx=sum(lm,tot),yy=sum(rm,tot);
        res=min(res,min(xx,yy));
        if(xx>yy) l=lm+1;
        else r=rm-1;
    }
    return res;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&s[i].l,&s[i].r);
        b[i]=s[i].r;
    }sort(b+1,b+n+1);

    cnt=unique(b+1,b+n+1)-b-1;
    for (int i=1;i<=n;i++)
        s[i].r=lower_bound(b+1,b+cnt+1,s[i].r)-b;
    sort(s+1,s+n+1,god);

    for (int i=1;i<=n;i++) add(s[i].r,1);

    int ans=1e9;
    for (int i=1,now;i<=n;i=now+1)
    {
        now=i;
        while(now<=n&&s[now].l==s[i].l) now++;
        now--;
        for (int j=i;j<=now;j++) add(s[j].r,0);

        ans=min(ans,get(now));
    }

    printf("%d\n",ans);

    return 0;
}