POJ 2464 Brownie Points II 树状数组||线段树

这题不是一般的恶心人,简直就是个神题。

参考了一个大牛的思路写了个树状数组版本的,不推荐用线段树,但是练练线段树也不错。

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;
}


线段树版本的以后奉上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值