POJ 2464 Brownie Points II (树状数组,难题)
题意:
在平面直角坐标系中给你N个点,stan和ollie玩一个游戏,首先stan在竖直方向上画一条直线,
该直线必须要过其中的某个点,然后ollie在水平方向上画一条直线,该直线的要求是要经过一个stan画的竖线经过的点。
这时候平面就被分割成了四块,两个人这时候会有一个得分,stan的得分是平面上第1、3象限内的点的个数,
ollie的得分是平面上第2、4象限内的点的个数,在统计的时候所画线上的点都不计算在内。
Stan的策略是,自己画一条竖线之后,Ollie有很多种选择,而ollie当然是让自己的越多越好。
对于Stan画的每条竖线,Stan都有可能获得最小的分数,求这些最小值中的最大值。
并且在该最大值的情况下,输出ollie可能获得的分数。
思路:
这个题目就是把POJ_2352数星星从一个象限拓展到了四个象限,把以每个点为中心四个象限内的点数都计算出来之后,
枚举Stan所划的那条竖线的位置,找出其中Stan所能获得的最小值以及在该最小值情况下Ollie所能获得的最大值,
然后根据实际情况更新结果即可。
具体求四个象限的点的个数,要用到树状数组,具体方法见代码。
注意:
让stan最小值中最大的取法有多种,把每一种中ollie所能取得的最大值算出来就行,而不必求出每一种中Ollie所有可能的取值。
本人写的程序很慢,922ms,在POJ AC的380+人中排名340+。。。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector> using namespace std;
const int maxn=;
const int INF=0x3f3f3f3f;
int n;
//存储以某点i为中心,它的左上方、右上方、左下方、右下方四个方块中的点的个数,不包括边界上的值。
int upper_left[maxn],upper_right[maxn],bottom_left[maxn],bottom_right[maxn];
//x坐标和y坐标离散的值
int cntx,cnty;
int c[maxn]; //树状数组,用于统计四个方向点的个数
vector<int> line[maxn]; //line[i]存储竖线i所经过的点的序号 struct Point{
int x,y;
int hx,hy; //x和y离散后的值,从1开始
int idx; //点的序号
}point[maxn]; //将点根据x坐标从小到大排序
bool cmpx(const Point t1,const Point t2){
return t1.x<t2.x;
}
//将点根据y坐标从小到大排序,若y相同则根据x从小到大排序
bool cmpy(const Point t1,const Point t2){
if(t1.y==t2.y)
return t1.x<t2.x;
else
return t1.y<t2.y;
} int lowbit(int x){
return x&(-x);
}
void update(int i){
while(i<=n){
c[i]++;
i+=lowbit(i);
}
}
int sum(int i){
int res=;
while(i){
res+=c[i];
i-=lowbit(i);
}
return res;
} void init(){
for(int i=;i<=n;i++){
line[i].clear();
}
memset(upper_left,,sizeof(upper_left));
memset(upper_right,,sizeof(upper_right));
memset(bottom_left,,sizeof(bottom_left));
memset(bottom_right,,sizeof(bottom_right));
}
int main()
{
while(scanf("%d",&n)!=EOF){
if(n==)
break;
init();
for(int i=;i<=n;i++){
scanf("%d%d",&point[i].x,&point[i].y);
point[i].idx=i;
}
sort(point+,point+n+,cmpx);
cntx=;
point[].hx=cntx;
line[cntx].push_back(point[].idx); //将该点压入对应的竖线中去
for(int i=;i<=n;i++){
if(point[i].x==point[i-].x)
point[i].hx=point[i-].hx;
else
point[i].hx=++cntx;
line[point[i].hx].push_back(point[i].idx);
}
sort(point+,point+n+,cmpy);
cnty=;
point[].hy=cnty;
for(int i=;i<=n;i++){
if(point[i].y==point[i-].y)
point[i].hy=point[i-].hy;
else
point[i].hy=++cnty;
} int num;
int samex[maxn]; //存储处于同一横线上,即x坐标相同的点的个数
int samey[maxn]; //存储处于同一竖线上,即y坐标相同的点的个数
memset(samex,,sizeof(samex));
memset(samey,,sizeof(samey));
memset(c,,sizeof(c));
/*
求位于某点“左下方”和“右下方”的点的个数:
按照y从小到大取,当取到某一点a时,那么每次求得的num即是 “x坐标小于a的x坐标,但y坐标可能会有相同的”点的个数,
所以要想求出点位于点a“左下方”的点的个数,还要用num减去“在点a之前加入的与a的y坐标相同”的点的个数,
即samey[point[i].hy]。 同样,在求位于点a“右下方”的点的个数,i-1-num包含了 “x坐标大于等于a的x坐标,y坐标小于a的y坐标”的点的个数,
因此还要用i-1-num减去“在点a之前加入的,与a的x坐标相同的点”的个数,即samex[point[i].hx]。 然后,再更新对应的samex、samey、update */
for(int i=;i<=n;i++){
num=sum(point[i].hx-); //注意num求得是“x坐标小于该点的x坐标”的点的个数
bottom_left[point[i].idx]=num-samey[point[i].hy];
bottom_right[point[i].idx]=i--num-samex[point[i].hx];
samey[point[i].hy]++;
samex[point[i].hx]++;
update(point[i].hx);
}
memset(c,,sizeof(c));
memset(samex,,sizeof(samex));
memset(samey,,sizeof(samey));
/*
求位于某点“左上方和右上方”的点的个数:
这里按照y从到小取,要注意的是当y相同时,先处理的是x较大的点。 当取到某点a时,每次求得的num值是“x坐标小于点a,但y坐标可能会有相同的”点的个数,
但由于当y相同时,取的顺序是按照x坐标从大到小取的,所以对结果并不影响,位于点a的“左上方”的点的个数即为num值。 而在求位于点a的“右上方”的点的个数时,剩余的n-i-num个点为“x坐标大于等于a的x坐标,y大于等于
a的y坐标”的点,所以还要减去“x坐标与a相同”的点的个数,即samex[point[i].hx],再减去“y坐标与a相同”的点的个数,
即samey[point[i].hy]。 然后,再更新对应的samex、samey、update
*/
for(int i=n;i>=;i--){
num=sum(point[i].hx-);
upper_left[point[i].idx]=num;
upper_right[point[i].idx]=n-i-num-right[point[i].hx]-left[point[i].hy];
left[point[i].hy]++;
right[point[i].hx]++;
update(point[i].hx);
}
int ans=-INF; //stan所能获取的最小值当中的最大值
int sums,sumo; //stan获得的数目,ollie获得的数目
int ollie[maxn],op=-;
//对每条竖线一条一条枚举即可
for(int i=;i<=cntx;i++){
int minsum=INF,v;
int tmp; //ollie能获取的最大值
//对每条竖线上的点枚举
for(int j=;j<line[i].size();j++){
v=line[i][j];
sums=upper_right[v]+bottom_left[v];
sumo=upper_left[v]+bottom_right[v];
if(sums<minsum){
minsum=sums;
tmp=sumo;
}
else if(sums==minsum){
tmp=max(tmp,sumo);
}
}
if(minsum>ans){
ans=minsum;
ollie[]=tmp;
op=;
}
else if(minsum==ans){
ollie[++op]=tmp;
}
}
printf("Stan: %d; ",ans);
printf("Ollie:");
sort(ollie,ollie+op+);
printf(" %d",ollie[]);
for(int i=;i<=op;i++){
if(ollie[i]!=ollie[i-])
printf(" %d",ollie[i]);
}
printf(";\n");
}
return ;
}
POJ 2464 Brownie Points II (树状数组,难题)的更多相关文章
- POJ 2464 Brownie Points II --树状数组
题意: 有点迷.有一些点,Stan先选择某个点,经过这个点画一条竖线,Ollie选择一个经过这条直接的点画一条横线.Stan选这两条直线分成的左下和右上部分的点,Ollie选左上和右下部分的点.Sta ...
- hdu 1156 && poj 2464 Brownie Points II (BIT)
2464 -- Brownie Points II Problem - 1156 hdu分类线段树的题.题意是,给出一堆点的位置,stan和ollie玩游戏,stan通过其中一个点画垂线,ollie通 ...
- POJ 2464 Brownie Points II(树状数组)
一开始还以为对于每根竖线,只要与过了任意一点的横线相交都可以呢,这样枚举两条线就要O(n^2),结果发现自己想多了... 其实是每个点画根竖线和横线就好,对于相同竖线统计(一直不包含线上点)右上左下总 ...
- POJ - 2464 Brownie Points II 【树状数组 + 离散化】【好题】
题目链接 http://poj.org/problem?id=2464 题意 在一个二维坐标系上 给出一些点 Stan 先画一条过一点的水平线 Odd 再画一条 过Stan那条水平线上的任一点的垂直线 ...
- UVA 10869 - Brownie Points II(树阵)
UVA 10869 - Brownie Points II 题目链接 题意:平面上n个点,两个人,第一个人先选一条经过点的垂直x轴的线.然后还有一个人在这条线上穿过的点选一点作垂直该直线的线,然后划分 ...
- POJ 2155 Matrix(二维树状数组,绝对具体)
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 20599 Accepted: 7673 Descripti ...
- poj 3321:Apple Tree(树状数组,提高题)
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 18623 Accepted: 5629 Descr ...
- POJ 2299 Ultra-QuickSort 逆序数 树状数组 归并排序 线段树
题目链接:http://poj.org/problem?id=2299 求逆序数的经典题,求逆序数可用树状数组,归并排序,线段树求解,本文给出树状数组,归并排序,线段树的解法. 归并排序: #incl ...
- poj 3321 Apple Tree(一维树状数组)
题目:http://poj.org/problem?id=3321 题意: 苹果树上n个分叉,Q是询问,C是改变状态.... 开始的处理比较难,参考了一下大神的思路,构图成邻接表 并 用DFS编号 白 ...
随机推荐
- kettle删除资源库中的转换或者作业
在资源库中新建转换,作业都很简单,那么加入现在不需要其中某个转换或者作业该怎么办呢? 下图是已经存在的转换跟作业 现在需要删除aa这个转换 操作步骤如下: 1.工具----资源库----探索资源库 出 ...
- Weka链接Mysql数据库
Weka简介 Weka的全名是怀卡托智能分析环境(Waikato Environment for Knowledge Analysis),是一款免费的,非商业化(与之对应的是SPSS公司商业数据挖掘产 ...
- hdu 1412 {A} + {B}
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=3282 {A} + {B} Description 给你两个集合,要求{A} + {B}.注:同一个集合 ...
- 历时八年,HTML5 标准终于完工了
万维网联盟(W3C)2014年10月29日泪流满面地宣布,经过几乎8年的艰辛努力,HTML5标准规范终于最终制定完成了,并已公开发布. 在此之前的几年时间里,已经有很多开发者陆续使用了HTML5的部分 ...
- P2763: [JLOI2011]飞行路线
然而WA了呀,这道分层图,也是不明白为什么WA了=-= ; maxn=; points=; type node=record f,t,l:longint; end; var n,m,k,i,j,u,v ...
- C语言中结构体的初始化
直接上例子: struct point { int x; int y; int z; } //常规写法 struct point pt1 = {100, 300, 200}; //初始化个数少于实际个 ...
- 通过find命令寻找文件并拷贝到一个指定目录方法详解
有这样的一个需求,需要将一部分符合条件的文件从一个目录拷贝到另一个目录中,可以通过使用find命令从源目录查找到符合条件的文件然后使用cp命令拷贝到目标目录 将通过find命令找到的文件拷贝到一个 ...
- 【BOZJ 1901】Zju2112 Dynamic Rankings
Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是 ...
- STL之multiset
参见http://www.cplusplus.com/reference/set/multiset/ template < class T, ...
- Spark系列—01 Spark集群的安装
一.概述 关于Spark是什么.为什么学习Spark等等,在这就不说了,直接看这个:http://spark.apache.org, 我就直接说一下Spark的一些优势: 1.快 与Hadoop的Ma ...