bzoj 4411 USACO16FEB 负载平衡Load Balancing(扫描线,树状数组,三分答案,前缀和)

来源:互联网 发布:数据清洗工具 编辑:程序博客网 时间:2024/06/01 07:42

题意:

给你一个矩阵,里面有些点,让你横向切一刀,纵向切一刀,使得得到的四个区域内的最大的点数最少。

思路:

首先考虑对于n大小在1000左右,直接二维前缀和预处理,枚举后,O(1)计算答案

对于n=100000,二维开不下,考虑加入数据结构维护区间和

于是加入树状数组,考虑直接枚举竖着的直线的横坐标,每次枚举时不断向树状数组加点(点的纵坐标)

这样对于外层循环的每一个i,当前的树状数组维护的都是横坐标 1~i 时,y方向上的点的区间个数和

下面举个例子

假设矩阵被分成这样      A3  A4

       A1  A2

那么A1中点的个数即为树状数组中sum(y),

为了求出A3,A2,一开始时维护x和y方向的一维前缀和

那么 A3=sum[x]-A1  A2=sum[y]-A1

A4=n-A1-A2-A3

这样的话就能把四个部分各自的点的数量表示出来

那么现在问题来了

我们不可能直接for来枚举横着的直线的纵坐标

又发现

min{max(A1,A2,A3,A4)}的值是个类似a<0的抛物线图像

满足上凸性质

所以可以用三分法对横坐标处理

三分判断条件见程序

最后横着的直线的y坐标在l处

直接计算答案


稍有问题,不过能过官方数据的WA代码

#include<bits/stdc++.h>using namespace std;const int N=101000;struct data{int x,y;}p[N];int n,temp[N*2],cnt=0;int id[10*N];int maxy=-1,maxx=-1,minx=1e9,miny=1e9;int ans=1e9;int e[N],sumy[2*N],sumx[2*N];bool comp(data a,data b){return a.x<b.x;}int lowbit(int x){return x&(-x);}void add(int x){while(x<N*2){e[x]++;x+=lowbit(x);}}int sum(int x){int res=0;while(x>0){res+=e[x];x-=lowbit(x);}return res;}void get_4(int *a,int x,int y){a[1]=sum(y);a[2]=sumy[y]-a[1];a[3]=sumx[x]-a[1];a[4]=n-a[1]-a[2]-a[3];sort(a+1,a+5);}void pre(){cin>>n;for(int i=1;i<=n;i++){cin>>p[i].x>>p[i].y;temp[++cnt]=p[i].x;temp[++cnt]=p[i].y;maxy=max(maxy,p[i].y);maxx=max(maxx,p[i].x);minx=min(minx,p[i].x);miny=min(miny,p[i].y);}sort(temp+1,temp+cnt+1);cnt=unique(temp+1,temp+cnt+1)-temp-1;for(int i=1;i<=cnt;i++)id[temp[i]]=i;sort(p+1,p+n+1,comp);for(int i=1;i<=n;i++) sumy[id[p[i].y]]++;for(int i=1;i<=cnt;i++) sumy[i]+=sumy[i-1];for(int i=1;i<=n;i++) sumx[id[p[i].x]]++;for(int i=1;i<=cnt;i++) sumx[i]+=sumx[i-1];}bool xiaoyu(int *a1,int *a2){for(int i=4;i>=1;i--){if(a1[i]>a2[i])return 0;if(a1[i]<a2[i])return 1;}}void solve(){int now=1;for(int i=1;i<=n;i++){for(int j=now;j<=n;j++)if(p[j].x<=p[i].x)add(id[p[j].y]);else{now=j;break;}int l=id[miny],r=id[maxy];int a1[5],a2[5],m1,m2;while(l<r){m1=l+(r-l)/3;m2=r-(r-l)/3;get_4(a1,id[p[i].x],m1);get_4(a2,id[p[i].x],m2);if(xiaoyu(a1,a2))r=m2-1;else l=m1+1;}get_4(a1,id[p[i].x],l);ans=min(a1[4],ans);}cout<<ans;}int main(){//freopen("in.in","r",stdin);pre();solve();}


阅读全文
0 0
原创粉丝点击