题意:
在平面直角坐标系中给你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+。。。

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <algorithm>
  5. #include <vector>
  6.  
  7. using namespace std;
  8. const int maxn=;
  9. const int INF=0x3f3f3f3f;
  10. int n;
  11. //存储以某点i为中心,它的左上方、右上方、左下方、右下方四个方块中的点的个数,不包括边界上的值。
  12. int upper_left[maxn],upper_right[maxn],bottom_left[maxn],bottom_right[maxn];
  13. //x坐标和y坐标离散的值
  14. int cntx,cnty;
  15. int c[maxn]; //树状数组,用于统计四个方向点的个数
  16. vector<int> line[maxn]; //line[i]存储竖线i所经过的点的序号
  17.  
  18. struct Point{
  19. int x,y;
  20. int hx,hy; //x和y离散后的值,从1开始
  21. int idx; //点的序号
  22. }point[maxn];
  23.  
  24. //将点根据x坐标从小到大排序
  25. bool cmpx(const Point t1,const Point t2){
  26. return t1.x<t2.x;
  27. }
  28. //将点根据y坐标从小到大排序,若y相同则根据x从小到大排序
  29. bool cmpy(const Point t1,const Point t2){
  30. if(t1.y==t2.y)
  31. return t1.x<t2.x;
  32. else
  33. return t1.y<t2.y;
  34. }
  35.  
  36. int lowbit(int x){
  37. return x&(-x);
  38. }
  39. void update(int i){
  40. while(i<=n){
  41. c[i]++;
  42. i+=lowbit(i);
  43. }
  44. }
  45. int sum(int i){
  46. int res=;
  47. while(i){
  48. res+=c[i];
  49. i-=lowbit(i);
  50. }
  51. return res;
  52. }
  53.  
  54. void init(){
  55. for(int i=;i<=n;i++){
  56. line[i].clear();
  57. }
  58. memset(upper_left,,sizeof(upper_left));
  59. memset(upper_right,,sizeof(upper_right));
  60. memset(bottom_left,,sizeof(bottom_left));
  61. memset(bottom_right,,sizeof(bottom_right));
  62. }
  63. int main()
  64. {
  65. while(scanf("%d",&n)!=EOF){
  66. if(n==)
  67. break;
  68. init();
  69. for(int i=;i<=n;i++){
  70. scanf("%d%d",&point[i].x,&point[i].y);
  71. point[i].idx=i;
  72. }
  73. sort(point+,point+n+,cmpx);
  74. cntx=;
  75. point[].hx=cntx;
  76. line[cntx].push_back(point[].idx); //将该点压入对应的竖线中去
  77. for(int i=;i<=n;i++){
  78. if(point[i].x==point[i-].x)
  79. point[i].hx=point[i-].hx;
  80. else
  81. point[i].hx=++cntx;
  82. line[point[i].hx].push_back(point[i].idx);
  83. }
  84. sort(point+,point+n+,cmpy);
  85. cnty=;
  86. point[].hy=cnty;
  87. for(int i=;i<=n;i++){
  88. if(point[i].y==point[i-].y)
  89. point[i].hy=point[i-].hy;
  90. else
  91. point[i].hy=++cnty;
  92. }
  93.  
  94. int num;
  95. int samex[maxn]; //存储处于同一横线上,即x坐标相同的点的个数
  96. int samey[maxn]; //存储处于同一竖线上,即y坐标相同的点的个数
  97. memset(samex,,sizeof(samex));
  98. memset(samey,,sizeof(samey));
  99. memset(c,,sizeof(c));
  100. /*
  101. 求位于某点“左下方”和“右下方”的点的个数:
  102. 按照y从小到大取,当取到某一点a时,那么每次求得的num即是 “x坐标小于a的x坐标,但y坐标可能会有相同的”点的个数,
  103. 所以要想求出点位于点a“左下方”的点的个数,还要用num减去“在点a之前加入的与a的y坐标相同”的点的个数,
  104. 即samey[point[i].hy]。
  105.  
  106. 同样,在求位于点a“右下方”的点的个数,i-1-num包含了 “x坐标大于等于a的x坐标,y坐标小于a的y坐标”的点的个数,
  107. 因此还要用i-1-num减去“在点a之前加入的,与a的x坐标相同的点”的个数,即samex[point[i].hx]。
  108.  
  109. 然后,再更新对应的samex、samey、update
  110.  
  111. */
  112. for(int i=;i<=n;i++){
  113. num=sum(point[i].hx-); //注意num求得是“x坐标小于该点的x坐标”的点的个数
  114. bottom_left[point[i].idx]=num-samey[point[i].hy];
  115. bottom_right[point[i].idx]=i--num-samex[point[i].hx];
  116. samey[point[i].hy]++;
  117. samex[point[i].hx]++;
  118. update(point[i].hx);
  119. }
  120. memset(c,,sizeof(c));
  121. memset(samex,,sizeof(samex));
  122. memset(samey,,sizeof(samey));
  123. /*
  124. 求位于某点“左上方和右上方”的点的个数:
  125. 这里按照y从到小取,要注意的是当y相同时,先处理的是x较大的点。
  126.  
  127. 当取到某点a时,每次求得的num值是“x坐标小于点a,但y坐标可能会有相同的”点的个数,
  128. 但由于当y相同时,取的顺序是按照x坐标从大到小取的,所以对结果并不影响,位于点a的“左上方”的点的个数即为num值。
  129.  
  130. 而在求位于点a的“右上方”的点的个数时,剩余的n-i-num个点为“x坐标大于等于a的x坐标,y大于等于
  131. a的y坐标”的点,所以还要减去“x坐标与a相同”的点的个数,即samex[point[i].hx],再减去“y坐标与a相同”的点的个数,
  132. 即samey[point[i].hy]。
  133.  
  134. 然后,再更新对应的samex、samey、update
  135. */
  136. for(int i=n;i>=;i--){
  137. num=sum(point[i].hx-);
  138. upper_left[point[i].idx]=num;
  139. upper_right[point[i].idx]=n-i-num-right[point[i].hx]-left[point[i].hy];
  140. left[point[i].hy]++;
  141. right[point[i].hx]++;
  142. update(point[i].hx);
  143. }
  144. int ans=-INF; //stan所能获取的最小值当中的最大值
  145. int sums,sumo; //stan获得的数目,ollie获得的数目
  146. int ollie[maxn],op=-;
  147. //对每条竖线一条一条枚举即可
  148. for(int i=;i<=cntx;i++){
  149. int minsum=INF,v;
  150. int tmp; //ollie能获取的最大值
  151. //对每条竖线上的点枚举
  152. for(int j=;j<line[i].size();j++){
  153. v=line[i][j];
  154. sums=upper_right[v]+bottom_left[v];
  155. sumo=upper_left[v]+bottom_right[v];
  156. if(sums<minsum){
  157. minsum=sums;
  158. tmp=sumo;
  159. }
  160. else if(sums==minsum){
  161. tmp=max(tmp,sumo);
  162. }
  163. }
  164. if(minsum>ans){
  165. ans=minsum;
  166. ollie[]=tmp;
  167. op=;
  168. }
  169. else if(minsum==ans){
  170. ollie[++op]=tmp;
  171. }
  172. }
  173. printf("Stan: %d; ",ans);
  174. printf("Ollie:");
  175. sort(ollie,ollie+op+);
  176. printf(" %d",ollie[]);
  177. for(int i=;i<=op;i++){
  178. if(ollie[i]!=ollie[i-])
  179. printf(" %d",ollie[i]);
  180. }
  181. printf(";\n");
  182. }
  183. return ;
  184. }

POJ 2464 Brownie Points II (树状数组,难题)的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. POJ 2155 Matrix(二维树状数组,绝对具体)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Descripti ...

  7. poj 3321:Apple Tree(树状数组,提高题)

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18623   Accepted: 5629 Descr ...

  8. POJ 2299 Ultra-QuickSort 逆序数 树状数组 归并排序 线段树

    题目链接:http://poj.org/problem?id=2299 求逆序数的经典题,求逆序数可用树状数组,归并排序,线段树求解,本文给出树状数组,归并排序,线段树的解法. 归并排序: #incl ...

  9. poj 3321 Apple Tree(一维树状数组)

    题目:http://poj.org/problem?id=3321 题意: 苹果树上n个分叉,Q是询问,C是改变状态.... 开始的处理比较难,参考了一下大神的思路,构图成邻接表 并 用DFS编号 白 ...

随机推荐

  1. Node.js学习笔记 01 搭建静态服务器

    希望这篇文章能解决你这样一个问题:“我现在已经了解了一些Node.Js基本概念了,怎么搭一台静态服务器呢?” 请参考一下博主的前两篇文章: 完全面向于初学者的Node.js指南 Node.Js的Mod ...

  2. java遍历Map的几种方式

    1.遍历map的几种方式:private Hashtable<String, String> emails = new Hashtable<String, String>(); ...

  3. RMAN - 备份异机恢复

    OS: Oracle Linux Server release 5.7 DB: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - ...

  4. Sql Server 语句

    ##目录 #####清除缓存 DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; SELECT stock.IdStock, stock.Descr FROM [In ...

  5. golang的++与--

    http://godoc.golangtc.com/doc/faq#inc_dec 简单地说, 在golang中++,--操作是语句而不是表达式. 所以a=b++, return x++之类绝对提示错 ...

  6. JVM规范小结

    JVM规范组成: 1. 字节码(ByteCode): 以Class或Interface为基本单位, 具有固定结构. 2. 指令集(InstructionSet): 每个指令用一个字节表示, 最多256 ...

  7. Your First ASP.NET 5 Application on a Mac

    Your First ASP.NET 5 Application on a Mac By Daniel Roth, Steve Smith, Rick Anderson ASP.NET 5 is cr ...

  8. iOS学习之UIView

    一.UI编程概述      1.UI的本意是用户界面,是英文User和Interface的缩写.      2.UI设计则是指对软件的人机交互.操作逻辑.界面美观的整体设计.      3.软件设计可 ...

  9. homework-03 扑街。。

    1.思路 我的思路是利用进程间通信间来实现题目要求. 第一次打开的程序与第二次打开的程序并不是同一个进程,故需要进程间通信来是传递信息. windows下进程间通信的方式有很多,如文件映射.共享内存. ...

  10. [shell基础]——算术运算

    shell只支持整数运算.一般可用let.expr.declare.$[]实现. 更精准的运算建议使用Linux下的bc工具——一款高精度计算语言. 1. let是shell内建的整数运算命令 ## ...