usaco 2016 Feb 负载平衡

题目大意:平面上一堆点,用两条平行于坐标轴的直线将其分为四部分,使得点数最多的一部分最少

第一维枚举,第二维三分,点集用两棵树状数组维护

#include<bits/stdc++.h>
#define maxn 100010
using namespace std;
inline int read(){
    int s=0;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar())s=s*10+ch-'0';
    return s;
}
int n;
struct node{
    int x,y;
    int cntx,cnty;
}s[maxn];
int cmp1(node a,node b){return a.x<b.x;}
int cmp2(node a,node b){return a.y<b.y;}
int c1[maxn];
int c2[maxn];
void add(int a[],int x,int v){
    for(;x<=n;x+=x&-x)a[x]+=v;
}
int ask(int a[],int x){
    int ans=0;
    for(;x;x-=x&(-x))ans+=a[x];
    return ans;
}
int get(){
    int L=1,R=n,mid1,mid2,k1,k2,p1,p2;
    int sum1=ask(c1,n);
    int sum2=ask(c2,n);
    while(R-L>=3){
        mid1=(L+L+R)/3,mid2=(L+R+R)/3;
        p1=ask(c1,mid1);p2=ask(c2,mid1);
        k1=max(max(p1,sum1-p1),max(p2,sum2-p2));
        p1=ask(c1,mid2);p2=ask(c2,mid2);
        k2=max(max(p1,sum1-p1),max(p2,sum2-p2));
        if(k1>k2)L=mid1;else R=mid2;
    }
    int ans=(1<<30);
    for(int i=L;i<=R;++i){
        p1=ask(c1,i);p2=ask(c2,i);
        ans=min(ans,max(max(p1,sum1-p1),max(p2,sum2-p2)));
    }return ans;
}
int main(){
    freopen("Load_Balancing.in","r",stdin);
    freopen("Load_Balancing.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i){
        s[i].x=read();s[i].y=read();
    }
    sort(s+1,s+n+1,cmp2);
    s[1].cnty=1;
    for(int i=2;i<=n;++i)
        if(s[i].y==s[i-1].y)s[i].cnty=s[i-1].cnty;
        else s[i].cnty=s[i-1].cnty+1;
    sort(s+1,s+n+1,cmp1);
    s[1].cntx=1;
    for(int i=2;i<=n;++i)
        if(s[i].x==s[i-1].x)s[i].cntx=s[i-1].cntx;
        else s[i].cntx=s[i-1].cntx+1;
    for(int i=1;i<=n;++i)add(c2,s[i].cnty,1);
    int L=1,R=s[n].cntx,now=1,ans=(1<<30);
    for(int i=L;i<=R+1&&now<=n;++i){
        while(s[now].cntx<=i&&now<=n)add(c2,s[now].cnty,-1),add(c1,s[now].cnty,1),now++;
        int k=get();
        if(k<ans)ans=k;
    }printf("%d
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/117208-/p/5349859.html