POJ 2464 Brownie Points II(树状数组)

  一开始还以为对于每根竖线,只要与过了任意一点的横线相交都可以呢,这样枚举两条线就要O(n^2),结果发现自己想多了。。。 

  其实是每个点画根竖线和横线就好,对于相同竖线统计(一直不包含线上点)右上左下总点数的最小值,最后不同竖线求一个最大值。对于每条等于这个最小值最大化的竖线都找一个右下与左上的最大值,排序输出即可。注意这儿排序后需要去重

  思想倒是不难,主要就是麻烦。只需要分别离散化x轴,y轴的点,然后枚举每个点找到四个方向的其他总点数,这儿用树状数组可以简单解决。但是注意空间问题不能开二维,开一维排序x轴,再左右扫一遍,一边计算一边添加点即可,注意x y轴线上的点要减去。先扫一边找到最小值最大化的值与每条竖线包含哪些点,再扫一遍找到等于那个值的竖线中的最大右下左上和

代码写得很麻烦

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=1<<30;
const double Pi=acos(-1.0);
const int Max=200010;
int bit[Max];
struct node
{
    int xx1,yy1;
    int lup,rup,ldo,rdo;
} poi[Max];
int n;
bool cmp1(struct node p1,struct node p2)
{
    if(p1.xx1==p2.xx1)
        return p1.yy1<p2.yy1;
    return p1.xx1<p2.xx1;
}
bool cmp2(struct node p1,struct node p2)
{
    return p1.yy1<p2.yy1;
}
int lowbit(int x)
{
    return x&(-x);
}
void Add(int y)
{
    while(y<=n)
    {
        bit[y]++;
        y+=lowbit(y);
    }
    return;
}
int Sum(int y)
{
    if(!y)
        return 0;
    int sum=0;
    while(y>0)
    {
        sum+=bit[y];
        y-=lowbit(y);
    }
    return sum;
}
void Dtz()//离散化
{
    sort(poi,poi+n,cmp2);
    int m=1;
    poi[n].yy1=Inf;
    for(int i=0; i<n; i++)
    {
        if(poi[i].yy1!=poi[i+1].yy1)//注意不能和前一个进行比较,因为前一个已经被赋值
            poi[i].yy1 = m++;
        else
            poi[i].yy1 = m;
    }

    sort(poi,poi+n,cmp1);
    m=1;
    poi[n].xx1=Inf;
    for(int i=0; i<n; i++)
    {
        if(poi[i].xx1!=poi[i+1].xx1)
            poi[i].xx1 = m++;
        else
            poi[i].xx1 = m;
    }
    return ;
}
int tem[Max],minx[Max],pos[Max];
void Solve()
{
    int sum;
    memset(bit,0,sizeof(bit));
    for(int i=0; i<n; i++) //边添加边查询
    {
        if(i!=0&&poi[i].xx1==poi[i-1].xx1)
            sum++;
        else
            sum=0;
        poi[i].ldo=Sum(poi[i].yy1-1)-sum;//减一,避免y轴相同的点被计算
        poi[i].lup=Sum(n)-Sum(poi[i].yy1);
        Add(poi[i].yy1);
    }

    memset(bit,0,sizeof(bit));
    for(int i=n-1; i>=0; i--)
    {
        if(i!=n-1&&poi[i].xx1==poi[i+1].xx1)
            sum++;
        else
            sum=0;
        poi[i].rdo=Sum(poi[i].yy1-1);
        poi[i].rup=Sum(n)-Sum(poi[i].yy1)-sum;
        Add(poi[i].yy1);
    }

    int manx=0,mans;//统计
    int coun=0,cnt=0;
    minx[0]=Inf;
    for(int i=0; i<n; i++)//计算最小值最大的是多少
    {
        if(!i||poi[i].xx1==poi[i-1].xx1)
        {
            if(poi[i].rup+poi[i].ldo<minx[coun])
            minx[coun]=poi[i].rup+poi[i].ldo;
        }
    else
    {
        manx=max(manx,minx[coun]);
        pos[coun++]=i;//每条同x轴的最后一个的后一个下标
        minx[coun]=Inf;
         if(poi[i].rup+poi[i].ldo<minx[coun])
            minx[coun]=poi[i].rup+poi[i].ldo;
    }
    }
    pos[coun]=n;
    manx=max(manx,minx[coun]);

    for(int i=0;i<=coun;i++)
    {
    if(minx[i]==manx)//此x轴可用
    {
        mans=0;
        for(int j=i==0?0:pos[i-1];j<pos[i];j++)
        mans=max(mans,poi[j].lup+poi[j].rdo);
        tem[cnt++]=mans;
    }
    }

    printf("Stan: %d; Ollie:",manx);
    sort(tem,tem+cnt);
    int cntt=0;
    for(int i=1;i<cnt;i++)//去重
        if(tem[i]!=tem[cntt])
        tem[++cntt]=tem[i];
    for(int i=0; i<=cntt; i++)
        printf(" %d",tem[i]);
    printf(";
");
    return ;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=0; i<n; i++)
            scanf("%d %d",&poi[i].xx1,&poi[i].yy1);
        Dtz();//离散化
        Solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/5863530.html