Stan and Ollie play the game of Odd Brownie Points. Some brownie points are located in the plane, at integer coordinates. Stan plays first and places a vertical line in the plane. The line must go through a brownie point and may cross many (with the same x-coordinate). Then Ollie places a horizontal line that must cross a brownie point already crossed by the vertical line.
Those lines divide the plane into four quadrants. The quadrant containing points with arbitrarily large positive coordinates is the top-right quadrant.

The players score according to the number of brownie points in the quadrants. If a brownie point is crossed by a line, it doesn't count. Stan gets a point for each (uncrossed) brownie point in the top-right and bottom-left quadrants. Ollie gets a point for each (uncrossed) brownie point in the top-left and bottom-right quadrants.

Stan and Ollie each try to maximize his own score. When Stan plays, he considers the responses, and chooses a line which maximizes his smallest-possible score.

Input

Input contains a number of test cases. The data of each test case appear on a sequence of input lines. The first line of each test case contains a positive odd integer 1 < n < 200000 which is the number of brownie points. Each of the following n lines contains two integers, the horizontal (x) and vertical (y) coordinates of a brownie point. No two brownie points occupy the same place. The input ends with a line containing 0 (instead of the n of a test).

Output

For each input test, print a line of output in the format shown below. The first number is the largest score which Stan can assure for himself. The remaining numbers are the possible (high) scores of Ollie, in increasing order.

Sample Input

11
3 2
3 3
3 4
3 6
2 -2
1 -3
0 0
-3 -3
-3 -2
-3 -4
3 -7
0

Sample Output

Stan: 7; Ollie: 2 3;

简述一下题意,给你一些点的x,y坐标,过一点做垂线,再做一条水平线,且该水平线必须经过已经被第一条垂线穿过的点,将所有点分成了4份,Stan是左下右上点个数之和,Ollie是左上右下,
求出Stan的值,使其最小值最大,并且输出该条垂线下,Stan取该值时,Ollie值的最大值,升序打印。
思路:读题意,求个数之和,想到二维树状数组,看数据范围,变成偏序问题,离散化后一维树状数组即可,本题的细节主要是在如何求这四份,树状数组可以求出左下区域,那么就分别维护每个点上下左右各有多少点,结合左下就可以求出其他区域,如图:

TL = 该点左侧的点-BL, TR = 该点上侧的点-TL, BR = 该点右侧的点-TR


细节代码中有注释(补到线段树和扫描线再做一次


using namespace std;
#define lowbit(x) ((x)&(-x))
typedef long long LL; const int maxm = 2e5+;
const int INF = 0x3f3f3f3f; int x[maxm], y[maxm], numx[maxm], numy[maxm], Left[maxm], Right[maxm], \
Upper[maxm], Lower[maxm], n, totx, toty, C[maxm], ally[maxm], allx[maxm], \
sumLeft[maxm], sumRight[maxm], sumUpper[maxm], sumLower[maxm], sumx[maxm], sumy[maxm], \
ans1[maxm], ans2[maxm];
bool vis[maxm]; void init() {
totx = toty = ;
memset(ans1, , sizeof(ans1)), memset(ans2, -, sizeof(ans2));
memset(C, , sizeof(C)), memset(numx, , sizeof(numx)), memset(numy, , sizeof(numy));
memset(sumx, , sizeof(sumx)), memset(sumy, , sizeof(sumy)), memset(vis, , sizeof(vis));
} void add(int pos, int val) {
for(; pos <= toty; pos += lowbit(pos))
C[pos] += val;
} int getsum(int pos) {
int ret = ;
for(; pos; pos -= lowbit(pos))
ret += C[pos];
return ret;
} struct Node {
int x, y;
Node(){}
bool operator<(const Node &a) const {
return x < a.x || (x == a.x && y < a.y);
}
} Nodes[maxm]; int main() {
while(scanf("%d", &n) && n) {
init();
// 读入并对x,y离散化
for(int i = ; i <= n; ++i) {
scanf("%d%d", &x[i], &y[i]);
allx[++totx] = x[i], ally[++toty] = y[i];
}
sort(allx+, allx++totx), sort(ally+,ally++toty);
int lenx = unique(allx+, allx++totx)-allx-, leny = unique(ally+,ally++toty)-ally-;
int nodenum = ;
for(int i = ; i <= n; ++i) {
Nodes[++nodenum].x = lower_bound(allx+,allx+lenx+, x[i]) - allx;
Nodes[nodenum].y = lower_bound(ally+,ally+leny+, y[i]) - ally;
}
sort(Nodes+, Nodes+nodenum+);
// 求出每个点上下左右垂直有多少个点
for(int i = ; i <= nodenum; ++i) {
Lower[i] = numx[Nodes[i].x]++;
Left[i] = numy[Nodes[i].y]++;
}
for(int i = ; i <= nodenum; ++i) {
Upper[i] = numx[Nodes[i].x] - Lower[i] - ;
Right[i] = numy[Nodes[i].y] - Left[i] - ;
}
// 求出坐标xi=1,2,的左侧 yi=1,2,的下侧 一共有多少个点 水平/垂直线(包括该线)
for(int i = ; i <= lenx; ++i) {
sumx[i] = sumx[i-] + numx[i];
}
for(int i = ; i <= leny; ++i) {
sumy[i] = sumy[i-] + numy[i];
}
// 计算每个点上下左右侧一共有几个点
for(int i = ; i <= nodenum; ++i) {
int x = Nodes[i].x, y = Nodes[i].y;
sumLeft[i] = sumx[x-];
sumRight[i] = sumx[lenx] - sumx[x];
sumLower[i] = sumy[y-];
sumUpper[i] = sumy[leny] - sumy[y];
}
for(int i = ; i <= nodenum; ++i) {
int x = Nodes[i].x, y = Nodes[i].y;
int BL = getsum(y-) - Lower[i];
int TL = sumLeft[i] - BL - Left[i];
int TR = sumUpper[i] - TL - Upper[i];
int BR = sumLower[i] - BL - Lower[i];
add(y, );
if(BL + TR < ans1[x]) {
ans1[x] = BL + TR, ans2[x] = TL + BR;
} else if(BL + TR == ans1[x]) ans2[x] = max(ans2[x], TL + BR);
}
int ans = ;
for(int i = ; i <= lenx; ++i)
if(ans1[i] < INF)
ans = max(ans, ans1[i]);
printf("Stan: %d; Ollie:",ans);
for(int i = ; i <= lenx; ++i)
if(ans1[i] == ans) vis[ans2[i]] = true;
for(int i = ; i <= n; ++i)
if(vis[i])
printf(" %d", i);
printf(";\n");
}
}


												

Day6 - E - Brownie Points II POJ - 2464的更多相关文章

  1. hdu 1156 && poj 2464 Brownie Points II (BIT)

    2464 -- Brownie Points II Problem - 1156 hdu分类线段树的题.题意是,给出一堆点的位置,stan和ollie玩游戏,stan通过其中一个点画垂线,ollie通 ...

  2. UVA10869 - Brownie Points II(线段树)

    UVA10869 - Brownie Points II(线段树) 题目链接 题目大意:平面上有n个点,Stan和Ollie在玩游戏,游戏规则是:Stan先画一条竖直的线作为y轴,条件是必需要经过这个 ...

  3. UVA 10869 - Brownie Points II(树阵)

    UVA 10869 - Brownie Points II 题目链接 题意:平面上n个点,两个人,第一个人先选一条经过点的垂直x轴的线.然后还有一个人在这条线上穿过的点选一点作垂直该直线的线,然后划分 ...

  4. POJ - 2464 Brownie Points II 【树状数组 + 离散化】【好题】

    题目链接 http://poj.org/problem?id=2464 题意 在一个二维坐标系上 给出一些点 Stan 先画一条过一点的水平线 Odd 再画一条 过Stan那条水平线上的任一点的垂直线 ...

  5. POJ 2464 Brownie Points II (树状数组,难题)

    题意:在平面直角坐标系中给你N个点,stan和ollie玩一个游戏,首先stan在竖直方向上画一条直线,该直线必须要过其中的某个点,然后ollie在水平方向上画一条直线,该直线的要求是要经过一个sta ...

  6. POJ 2464 Brownie Points II(树状数组)

    一开始还以为对于每根竖线,只要与过了任意一点的横线相交都可以呢,这样枚举两条线就要O(n^2),结果发现自己想多了... 其实是每个点画根竖线和横线就好,对于相同竖线统计(一直不包含线上点)右上左下总 ...

  7. POJ 2464 Brownie Points II --树状数组

    题意: 有点迷.有一些点,Stan先选择某个点,经过这个点画一条竖线,Ollie选择一个经过这条直接的点画一条横线.Stan选这两条直线分成的左下和右上部分的点,Ollie选左上和右下部分的点.Sta ...

  8. HDOJ-1156 Brownie Points II 线段树/树状数组(模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=1156 在一张二位坐标系中,给定n个点的坐标,玩一个划线游戏(线必须穿过点),Stan先手画一条垂直的线,然后Ol ...

  9. [转载]完全版线段树 by notonlysuccess大牛

    原文出处:http://www.notonlysuccess.com/ (好像现在这个博客已经挂掉了,在网上找到的全部都是转载) 今天在清北学堂听课,听到了一些很令人吃惊的消息.至于这消息具体是啥,等 ...

随机推荐

  1. js中怎么把类数组转化为数组

    说起伪数组,首先想到arguments, 这个我们函数参数的一个类数组,是类数组的代表. 1.拥有length属性,可以使用下标来访问元素,这两点和数组相同. 2.不能使用数组的方法,他们不能使用Ar ...

  2. GO测试

    测试 Go拥有一个轻量级的测试框架,它由 go test 命令和 testing 包构成. 你可以通过创建一个名字以 _test.go 结尾的,包含名为 TestXXX 且签名为 func (t *t ...

  3. 吴裕雄--天生自然ORACLE数据库学习笔记:表分区与索引分区

    create table ware_retail_part --创建一个描述商品零售的数据表 ( id integer primary key,--销售编号 retail_date date,--销售 ...

  4. 发送邮件#Python

    import yagmailusername='11@qq.com' #发件人邮箱qq='zhezlqiggd' #授权码,QQ邮箱可在设置账户获得mail_server='smtp.qq.com' ...

  5. nginx + keepalive 实现高可用

    https://blog.csdn.net/u010020099/article/details/82116474 ! Configuration File for keepalived global ...

  6. Linux centosVMware zabbix主动模式和被动模式、添加监控主机、添加自定义模板、处理图形中的乱码、自动发现

    一.主动模式和被动模式 主动或者被动是相对客户端来讲的 被动模式,服务端会主动连接客户端获取监控项目数据,客户端被动地接受连接,并把监控信息传递给服务端 主动模式,客户端会主动把监控数据汇报给服务端, ...

  7. 使用git下载一个项目

    1.安装好git之后创建一个库repository,用来保存git项目 2.进入repository之后,右击之后,选中 git bash here菜单选项 3.弹出命令界面之后输入命令: git c ...

  8. C++ class with pointer member(s)

    正如标题所示:这篇复习带有指针类型成员的class 设计类 考虑到会有以下操作,来设计类 { String s1(); String s2("hello"); String s3( ...

  9. Codeforces 1300E. Water Balance

    给你一个数列,有一个操作,将一段数字变成其和除以个数,求字典序最小的那一个,分析知,求字典序最小,就是求一个不下降序列,但我们此时有可以更改数字的操作,已知已经不下降的序列不会因为操作而变的更小,只有 ...

  10. IDEA工具java开发之 常用插件 git插件 追加提交 Code Review==代码评审插件 撤销提交 撤销提交 关联远程仓库 设置git 本地操作

    ◆git 插件 请先安装git for windows ,git客户端工具 平时开发中,git的使用都是用可视化界面,git命令需要不时复习,以备不时之需 1.环境准备 (1)设置git (2)本地操 ...