題意:在平面直角座標系中給你N個點,stan和ollie玩一個遊戲,首先stan在豎直方向上畫一條直線,該直線必須要過其中的某個點,然後ollie在水平方向上畫一條直線,該直線的要求是要經過一個stan之前畫過的點。 這時候平面就被分割成了四塊,兩個人這時候會有一個得分,stan的得分是平面上第1、3象限內的點的個數,ollie的得分是平面上第2、4象限內的點的個數,在統計的時候在所畫線上的點都不計算在內。求最終stan使得自己的最差得分最高,並且輸出此時ollie的得分。
根據題目中的資料畫出來的圖是這樣的,兩邊的數字分別表示的是,低於當前點y座標的點的個數(用ol[]數組表示),高於當前點y座標的點的個數(用st[]數組表示),分別用這兩個數組建兩棵線段樹,表示Ollie的分數和stan的分數。處理出這樣的資料後,我們把座標以x從小到大排序,之後,每掃到一個x即是stan畫下了一條豎線,這時候,Ollie畫下的橫線就是每個掃到的點的y座標。
在status 1的時候,當Ollie取的橫線分別是y=-4、-3、-2時,stan的分數分別是st[-4]=9,st[-3]=7和st[-2]=5,而Ollie的分數分別是ol[-4]=1,ol[-3]=2和ol[-2]=4。(即分別線上段樹裡單點查詢這些點的值)
當掃第x=0的時候,原來屬於Ollie的3個點,即(-3,-4),(-3,-3),(-3,-3)已經是屬於stan,這怎麼線上段樹裡體現裡?當這時候,當Ollie選擇橫線的y是大於等於-3的時候,那麼(-3,-4)是點是屬於stan的,那麼我們就可以在stan的線段樹裡在區間[-3,7]裡加1(這就搞定了不是?),同理處理出(-3,-3),(-3,-2),而Ollie得分的處理方式是類似的,這樣的處理可以在status
1裡完成,所以當我們到達status 2的時候,只需要處理(0,0)這個點,之後,那麼我們在兩棵線段樹裡分別查詢y=0,即得到了在status 2時stan和Ollie的分數。
#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <algorithm>#include <map>using namespace std;#define LL(x) (x<<1)#define RR(x) (x<<1|1)#define MID(a,b) (a+((b-a)>>1))const int N=200005;struct Point{int x,y;void get(){scanf("%d%d",&x,&y);}bool operator<(const Point&b)const{ return x<b.x; }}p[N];struct node{int lft,rht;int flag[2];int mid(){return MID(lft,rht);}void init(int a,int b){flag[0]=a;flag[1]=b;}};int n,m,mi;vector<int> mx;map<int,int> H;int y[N],st[N],ol[N];struct Segtree{node tree[N*4];void down(int ind){for(int i=0;i<2;i++){tree[LL(ind)].flag[i]+=tree[ind].flag[i];tree[RR(ind)].flag[i]+=tree[ind].flag[i];tree[ind].flag[i]=0;}}void build(int lft,int rht,int ind){tree[ind].lft=lft;tree[ind].rht=rht;tree[ind].init(0,0);if(lft==rht) tree[ind].init(st[lft],ol[lft]);else{int mid=tree[ind].mid();build(lft,mid,LL(ind));build(mid+1,rht,RR(ind));}}void updata(int st,int ed,int ind,int type,int valu){int lft=tree[ind].lft,rht=tree[ind].rht;if(st<=lft&&rht<=ed) tree[ind].flag[type]+=valu;else {down(ind);int mid=tree[ind].mid();if(st<=mid) updata(st,ed,LL(ind),type,valu);if(ed> mid) updata(st,ed,RR(ind),type,valu);}}void query(int pos,int ind,int &mi,int &mx){if(tree[ind].lft==tree[ind].rht) {mi=tree[ind].flag[0];mx=tree[ind].flag[1];}else {down(ind);int mid=tree[ind].mid();if(pos<=mid) return query(pos,LL(ind),mi,mx);if(pos> mid) return query(pos,RR(ind),mi,mx);}}}seg;int main(){while(scanf("%d",&n),n){H.clear(); mx.clear(); mi=m=0;int id1=0,id2=0;for(int i=0;i<n;i++){p[i].get();y[i]=p[i].y;}sort(y,y+n);sort(p,p+n);H[y[0]]=0;for(int i=0;i<n;i++){if(y[m]!=y[i]){st[m]=n-i;y[++m]=y[i];ol[m]=i;H[y[m]]=m;}}st[m]=0;seg.build(0,m,1);while(id1<n){id2=id1;while(p[id1].x==p[id2].x){if(p[id2].y!=y[0]) seg.updata(H[y[0]],H[p[id2].y]-1,1,0,-1);if(p[id2].y!=y[m]) seg.updata(H[p[id2].y]+1,H[y[m]],1,1,-1);if(++id2>=n) break;}int mii=n,mxx=0;for(int i=id1;i<id2;i++){int tmp1,tmp2;seg.query(H[p[i].y],1,tmp1,tmp2);mii=min(mii,tmp1);mxx=max(mxx,tmp2);}if(mii==mi) mx.push_back(mxx);else if(mii>mi){mi=mii;mx.clear(); mx.push_back(mxx);}for(int i=id1;i<id2;i++){if(p[i].y!=y[0]) seg.updata(H[y[0]],H[p[i].y]-1,1,1,1);if(p[i].y!=y[m]) seg.updata(H[p[i].y]+1,H[y[m]],1,0,1);}id1=id2;}sort(mx.begin(),mx.end());mx.erase(unique(mx.begin(),mx.end()),mx.end());printf("Stan: %d; Ollie:",mi);for(int i=0;i<(int)mx.size();i++) printf(" %d",mx[i]);printf(";\n");}return 0;}