您的位置:首页 > Web前端

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

2017-06-05 15:26 267 查看
题意:

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

思路:

首先考虑对于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
;
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
,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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息