这题不是一般的恶心人,简直就是个神题。
参考了一个大牛的思路写了个树状数组版本的,不推荐用线段树,但是练练线段树也不错。
http://hi.baidu.com/czyuan_acm/blog/item/af6fe8a9177f7ef51e17a2ea.html
这道题用二分也可以做的,这里介绍下树状数组的做法。首先有n个点,过每个点可以做x,y轴,把平面切成BL, TL, TR, BR四个部分,我们现在的问题是如果快速的计算这四个部分的点的个数。
这样我们可以先预处理,先按y坐标排序,求出每个点正左方和正右方的点的个数LeftPoint[], RightPoint[],复杂度为O(n),同样我们再以x坐标排序,求出每个点正上方和正下方点的个数UpPoint[], DownPoint[]。还要求出比点i y坐标大的点的个数 LageY[]。注意:这里要进行下标映射,因为两次排序点的下标是不相同的。
然后按x坐标从小到大排序,x坐标相等则y坐标从小到大排序。我们可以把y坐标放在一个树状数组中。
对于第i个点,求出Getsum(y[i])即为BL的个数,然后Update(y[i])。由于现在是第i点,说明前面有i – 1个点, 那么
TL = i - 1 - LeftPoint[i]- BL;
TR = LargeY[i] - TL – UpPoint[i] ;
BR = n - BL - TL - TR - LeftPoint[i] - RightPont[i] - UpPoint[i] – DownPont[i] - 1;
这样我们就求出四个部分的点的个数,然后判断有没有当前解优,有的话就更新即可~~
/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define INF 2000000000
#define MAXN 210005
#define eps 1e-10
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct node
{
int x, y;
int id;
}p[MAXN];
bool cmp1(node x, node y)
{
if(x.x == y.x) return x.y < y.y;
return x.x < y.x;
}
bool cmp2(node x, node y)
{
if(x.y == y.y) return x.x < y.x;
return x.y < y.y;
}
int n;
int lft[MAXN], rht[MAXN], up[MAXN], down[MAXN], a[MAXN], id[MAXN], largey[MAXN];
void init()
{
for(int i = 0; i <= n; i++)
lft[i] = rht[i] = up[i] = down[i] = a[i] = largey[i] = 0;
}
int lowbit(int x)
{
return x & -x;
}
void modify(int x)
{
for(int i = x; i < MAXN; i += lowbit(i))
a[i]++;
}
int getsum(int x)
{
int sum = 0;
for(int i = x; i > 0; i -= lowbit(i))
sum += a[i];
return sum;
}
int main()
{
while(scanf("%d", &n) != EOF && n)
{
for(int i = 0; i < n; i++)
{
p[i].x = in();
p[i].y = in();
p[i].id = i;
}
init();
sort(p, p + n, cmp2);
for(int i = 1; i < n; i++)
{
if(p[i].y == p[i - 1].y) {lft[p[i].id] = lft[p[i - 1].id] + 1; }
if(p[n - i - 1].y == p[n - i].y) {rht[p[n - i - 1].id] = rht[p[n - i].id] + 1; largey[p[n - i - 1].id] = largey[p[n - i].id] ;}
else largey[p[n - i - 1].id] = i;
}
int tid = 1;
id[p[0].id] = tid;
for(int i = 1; i < n; i++)
{
if(p[i].y == p[i - 1].y) id[p[i].id] = tid;
else id[p[i].id] = ++tid;
}
sort(p, p + n, cmp1);
for(int i = 1; i < n; i++)
{
if(p[i].x == p[i - 1].x) down[p[i].id] = down[p[i - 1].id] + 1;
if(p[n - i - 1].x == p[n - i].x) up[p[n - i - 1].id] = up[p[n - i].id] + 1;
}
set<int>st;
int mx = 0;
int tx = p[0].x;
for(int i = 0; i < n; i++)
{
int xid = p[i].id;
int omax = -1, smax = -1;
while(i < n && p[i].x == tx)
{
int tsum = getsum(id[xid]);
modify(id[xid]);
int bl = tsum - lft[xid] - down[xid];
int tl = i - tsum;
int tr = largey[xid] - tl - up[xid];
int br = n - 1 - bl - tl - tr - rht[xid] - lft[xid] - up[xid] - down[xid];
int olie = tl + br;
if(olie > omax){omax = olie; smax = tr + bl;}
else if(olie == omax){smax = min(smax, tr + bl);}
i++;
xid = p[i].id;
}
if(i < n) tx = p[i--].x;
if(smax > mx)
{
mx = smax;
st.clear();
st.insert(omax);
}
else if(smax == mx) st.insert(omax);
}
printf("Stan: %d; Ollie:", mx);
set<int>::iterator it;
for(it = st.begin(); it != st.end(); it++)
printf(" %d", *it);
printf(";\n");
}
return 0;
}
线段树版本的以后奉上。