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. spring cloud spring boot JPA 克隆对象修改属性后 无法正常的执行save方法进行保存或者更新

    2019-12-1220:34:58 spring cloud spring boot JPA 克隆对象修改属性后 无法正常的执行save方法进行保存或者更新 未解决

  2. A股上市公司财报披露时间

    一.上市公司年报披露时间:每年1月1日——4月30日. 二.上市公司中年报披露时间:每年7月1日——8月30日. 三.上市公司季报披露时间: 1季报:每年4月1日——4月30日. 2季报(中报):每年 ...

  3. Python学习笔记007

    赋值运算符 num+=1 num=num+1 num-=1 num=num-1 num*=2 num=num*2 num/=2 num=num/2 num//=2 num=num//2 num%=2 ...

  4. List模拟栈

    import java.util.LinkedList; import java.util.List; import java.util.Scanner; public class Main<E ...

  5. luogu P4014 分配问题

    简单的费用流问题,每个人对每个任务连边,每个任务对汇点连,源点对每个人连,最大费用取反即可 #include<bits/stdc++.h> using namespace std; #de ...

  6. 图论初步<蒟蒻专属文章>

    前言:    图论乃noip之重要知识点,但有点难理解 本人因此吃过不少亏 因为本人实在太弱,所以此篇乃正宗<蒟蒻专属文章> 正文:(本文仅介绍图论中的重点.难点,其余部分略将或不讲) 图 ...

  7. .Net后台实现微信APP支付

    上一节分享了微信小程序支付的后台,这一节来分享一下微信APP支付的后台.微信APP支付和微信小程序差别不大,微信APP支付后台不需要微信登录凭证.后台下单时交易类型(trade_type)不再是&qu ...

  8. scrapy(创建scrapy工程)报错:“ ImportError:DLL load failed:找不到指定的模块”

    先要确定什么模块找不到 解决方法 windowa环境下加 ( --user) pip install -I cryptography --user

  9. 吴裕雄--天生自然HADOOP操作实验学习笔记:pig简介

    实验目的 了解pig的该概念和原理 了解pig的思想和用途 了解pig与hadoop的关系 实验原理 1.Pig 相比Java的MapReduce API,Pig为大型数据集的处理提供了更高层次的抽象 ...

  10. Linux --xrandr command

    Source: https://www.x.org/archive/current/doc/man/man1/xrandr.1.xhtml https://blog.csdn.net/syh_486_ ...