题意:
给Stan个点,玩家Stan先经过某个点画一条竖线,玩家Ollie再经过这条线上的某一点画一条竖线,这样将整个区域分为4个区域,左上和右下里的点是Stan的得分,左下和右上是Ollie的得分,问Stan最多能得多少分和在保证Stan的最高分的情况下Ollie能得的最高分是多少.注意Stan选择一条竖线后Ollie要站在有利于自己的情况下考虑。
分析:
这题的本质是在足够快的时间内对每个点算出:如果这个点最为最终将平面分成4份的点,两人的得分情况是什么。树状数组可以完成动态求和(动态求某个区间内元素数量),注意可以动态,所以可以通过控制访问点的顺序达到不同目的。
代码:
//poj 2464
//sepNINE
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
const int maxN=200024;
map<int,int> myMap;
struct BIT
{int c[maxN],n;BIT(){}BIT(int n0){clear(),n=n0;} void clear(){memset(c,0,sizeof(c));}int lowbit(int x){return x&(x^(x-1));}void modify(int i,int d){while(i<=n){c[i]+=d;i+=lowbit(i);}}int q(int i){int sum;for(sum=0;i>0;i-=lowbit(i))sum+=c[i];return sum;}
}myBIT;
struct Point
{int x,y;
}p[maxN];
int cmp(Point a,Point b)
{return a.y<b.y;
}int A[maxN],B[maxN],C[maxN],D[maxN],ans[maxN],tmp[maxN];
int firstByPoint[maxN],secondByPoint[maxN];
int firstByLine[maxN],secondByLine[maxN];
int cmp1(int a,int b)
{return a<b;
}int main()
{int n;while(scanf("%d",&n)==1&&n){myMap.clear();int i,x=0;for(i=1;i<=n;++i){scanf("%d%d",&p[i].x,&p[i].y);if(myMap[p[i].x]==0)myMap[p[i].x]=++x;}map<int,int>::iterator iter;for(iter=myMap.begin(),i=1;iter!=myMap.end();++iter,++i)iter->second=i;sort(p+1,p+1+n,cmp);myBIT.n=x;myBIT.clear();int num=0;for(i=1;i<=n;++i){//printf("deal: %d %d\n",p[i].x,p[i].y);int t=myMap[p[i].x],curY;if(i==1||p[i].y!=curY){curY=p[i].y;for(int j=0;j<num;++j)myBIT.modify(tmp[j],1);num=0;C[i]=myBIT.q(t-1);D[i]=myBIT.q(x)-myBIT.q(t); }else{C[i]=myBIT.q(t-1);D[i]=myBIT.q(x)-myBIT.q(t); }//printf("ans C%d D %d\n",C[i],D[i]);//printf("\n");tmp[num++]=t;}myBIT.clear();num=0;for(i=n;i>=1;--i){int t=myMap[p[i].x],curY; if(i==n||p[i].y!=curY){curY=p[i].y;for(int j=0;j<num;++j)myBIT.modify(tmp[j],1);A[i]=myBIT.q(t-1);B[i]=myBIT.q(x)-myBIT.q(t); num=0;}else{A[i]=myBIT.q(t-1);B[i]=myBIT.q(x)-myBIT.q(t); }tmp[num++]=t;} for(i=1;i<=n;++i){firstByPoint[i]=B[i]+C[i];secondByPoint[i]=A[i]+D[i];}for(i=1;i<=x;++i)secondByLine[i]=-1;for(i=1;i<=n;++i){int t=myMap[p[i].x];if(secondByPoint[i]>secondByLine[t]){secondByLine[t]=secondByPoint[i]; firstByLine[t]=firstByPoint[i];}else if(secondByPoint[i]==secondByLine[t]){firstByLine[t]=min(firstByLine[t],firstByPoint[i]);} }int maxx=-1;for(i=1;i<=x;++i)maxx=max(maxx,firstByLine[i]); int cnt=0;for(i=1;i<=x;++i)if(firstByLine[i]==maxx)ans[++cnt]=secondByLine[i];printf("Stan: %d; Ollie:",maxx);sort(ans+1,ans+1+cnt,cmp1);ans[0]=-1;for(i=1;i<=cnt;++i)if(ans[i]!=ans[i-1])printf(" %d",ans[i]);printf(";\n"); }return 0;
}