bzoj4411 [Usaco2016 Feb]Load balancing

http://www.elijahqi.win/archives/3059
Description

给出N个平面上的点。保证每一个点的坐标都是正奇数。
你要在平面上画两条线,一条是x=a,一条是y=b,且a和b都是偶数。
直线将平面划成4个部分,要求包含点数最多的那个部分点数最少。

Input

第一行一个数N。
接下来N行每行描述一个点
N<=100000
1<=x,y<=1000000

Output

输出一个数表示最少的点数。

Sample Input

7
7 3
5 5
7 13
3 1
11 7
5 3
9 1
Sample Output

2
HINT

Source

枚举横坐标 然后上下维护线段树 然后每次做的时候对于纵坐标二分一个位置

max(l1,l2)>=max(r1,r2) 然后取一下四个中的最大值返回即可 因为前面这个函数是单峰函数所以可以在线段树上直接二分即可

#include<cstdio>
#include<cctype>
#include<algorithm>
#define lc (x<<1)
#define rc (x<<1|1)
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=100010;
struct P{
    int x,y;
}point[N];
struct node{int v[2];}tree[N<<3];
int d[N],nn,d1[N],n1;
inline bool cmp(const P &a,const P &b){return a.x<b.x;}
inline void insert1(int x,int l,int r,int p,int v,int op){
    tree[x].v[op]+=v;if (l==r) return;int mid=l+r>>1;
    if(p<=mid) insert1(lc,l,mid,p,v,op);
    else insert1(rc,mid+1,r,p,v,op);
}
inline int query(int x,int l,int r,int l1,int r1,int l2,int r2){
    int mid=l+r>>1;
    int lv0=tree[lc].v[0],rv0=tree[rc].v[0];
    int lv1=tree[lc].v[1],rv1=tree[rc].v[1];
    if (l==r) {
        lv0=tree[x].v[0],rv0=tree[x].v[0];
        lv1=tree[x].v[1],rv1=tree[x].v[1];
        if (max(l1+lv0,l2+lv1)>=max(r1+rv0,r2+rv1))
        r1+=rv0,r2+=rv1;else l1+=lv0,l2+=lv1; 
        return max(max(l1,l2),max(r1,r2));
    }
    if (max(lv0+l1,lv1+l2)>=max(rv0+r1,rv1+r2))
    return query(lc,l,mid,l1,rv0+r1,l2,rv1+r2);
    else return query(rc,mid+1,r,l1+lv0,r1,l2+lv1,r2);
}
int main(){
    freopen("bzoj4411.in","r",stdin);
    int n=read();
    for (int i=1;i<=n;++i) point[i].x=read(),point[i].y=read(),d[++nn]=point[i].y,
    d1[++n1]=point[i].x;sort(d1+1,d1+n1+1);n1=unique(d1+1,d1+n1+1)-d1-1;
    sort(d+1,d+nn+1);nn=unique(d+1,d+nn+1)-d-1;
    for (int i=1;i<=n;++i){
        point[i].x=lower_bound(d1+1,d1+n1+1,point[i].x)-d1;
        point[i].y=lower_bound(d+1,d+nn+1,point[i].y)-d;
    }
    sort(point+1,point+n+1,cmp);int now=1,ans=inf;
    //for (int i=1;i<=n;++i) printf("%d %d\n",point[i].x,point[i].y);
    for (int i=1;i<=n;++i) insert1(1,1,nn,point[i].y,1,1);
    for (int i=1;i<=n1;++i){
        while(point[now].x==i) insert1(1,1,nn,point[now].y,-1,1),insert1(1,1,nn,point[now].y,1,0),++now;
        ans=min(ans,query(1,1,nn,0,0,0,0));
    }printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值