UVA10869 - Brownie Points II(线段树)

题目链接

题目大意:平面上有n个点,Stan和Ollie在玩游戏,游戏规则是:Stan先画一条竖直的线作为y轴,条件是必需要经过这个平面上的某一点,而ollie则画x轴,可是要在Stany画的y轴上经过的点中随意选择一点来作为原点画x轴。然后这个平面就被划分为4个象限,轴上的点都不算,1,3象限的点的个数就是Stan的得分,2,4就是ollie的得分。问Stan每画一条y轴,每条轴上都有个得分的最小值,求这些最小值中的最大值,而且输出这时ollie的得分。

解题思路:将y轴离散化建树,希望每次枚举一个点就能够得到这个点的Stan的得分。从左往右,从上往下处理每一个点,通过线段树能够得到y高度上的点的个数,就是第一象限的得分。然后每次查询完一个点就要将这个点在线段树中删掉。同理得到第三象限的得分。这题还要输出ollie的得分,而且要按顺序,用set来存储。

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>

using namespace std;

const int maxn = 2e5;
#define lson(x) (x<<1)
#define rson(x) ((x<<1) | 1)

int n;
vector<int> pos;
map<int, int>x, y;
set<int> score, vec;

struct Point {

    int x, y, score;
}p[maxn];

int cmp_x (const Point &a, const Point &b) {
    if (a.x == b.x)
        return a.y > b.y;
    return a.x < b.x;
}

struct Node {

    int l, r, v, addv;
    void set (int l, int r, int addv, int v) {

        this->l = l;
        this->r = r;
        this->v = v;
        this->addv = addv;
    }
}node[4 * maxn + 5];

void add_node (int u, int addv) {

    node[u].addv += addv;
    node[u].v += (node[u].r - node[u].l + 1) * addv;
}

void pushdown (int u) {

    if (node[u].addv) {
        add_node(lson(u), node[u].addv);
        add_node(rson(u), node[u].addv);
    }
}

void pushup (int u) {

    node[u].set (node[lson(u)].l, node[rson(u)].r, 0, node[lson(u)].v + node[rson(u)].v);
}

void build (int u, int l, int r) {

    if (l == r) {

        node[u].set (l, r, 0, y[pos[l]]);
        return ;
    }
    int m = (l + r)>>1;
    build (lson(u), l, m);
    build (rson(u), m + 1, r);
    pushup(u);
}

void update (int u, int l, int r, int add) {

    if (node[u].l >= l && node[u].r <= r) {
        add_node(u, add);
        return;
    }

    pushdown(u);
    int m = (node[u].l + node[u].r)>>1;
    if (l <= m)
        update (lson(u), l, r, add);
    if (r > m)
        update (rson(u), l, r, add);
    pushup(u);
}

int query (int u, int l, int r) {

    if (node[u].l >= l && node[u].r <= r)
        return node[u].v;

    pushdown(u);
    int m = (node[u].l + node[u].r)>>1;
    int ans = 0;
    if (l <= m)
        ans += query(lson(u), l, r);
    if (r > m)
        ans += query(rson(u), l, r);
    pushup(u);
    return ans;
}

void init () {

    x.clear();
    y.clear();
    pos.clear();

    for (int i = 0; i < n; i++) {

        scanf ("%d%d", &p[i].x, &p[i].y);
        p[i].score = 0;
        x[p[i].x]++;
        y[p[i].y]++;
        pos.push_back(p[i].y);
    }

    sort (pos.begin(), pos.end());
    sort (p, p + n, cmp_x);
    pos.erase(unique (pos.begin(), pos.end()), pos.end());
}

void solve_rtop () {

    int x;
    build(1, 0, (int)pos.size() - 1);
    for (int i = 0; i < n; i++) {

        x = lower_bound(pos.begin(), pos.end(), p[i].y) - pos.begin();
        if (x + 1 <= pos.size() - 1) {
            p[i].score += query(1, x + 1, pos.size() - 1);
            //printf ("%d %d %d\n", p[i].x, p[i].y, x);
        }
        update (1, x, x, -1);
    }
}

void solve_lboutom () {

    int x;
    build(1, 0, (int)pos.size() - 1);
    for (int i = n - 1; i >= 0; i--) {

        x = lower_bound(pos.begin(), pos.end(), p[i].y) - pos.begin();
        if (x - 1 >= 0) {
            p[i].score += query (1, 0, x - 1);
            //printf ("%d %d %d\n", p[i].x, p[i].y, p[i].score);
        }
        update (1, x, x, -1);
    }
}

void add_ans (int tmp) {

    for (set<int>::iterator it = vec.begin(); it != vec.end(); it++)
        score.insert(n - tmp - x[p[*it].x] - y[p[*it].y] + 1);
}

void solve () {

    init();
    solve_lboutom();
    solve_rtop();
    score.clear();
    vec.clear();

    int ans = -1;
    int tmp = p[0].score;
    int pre = p[0].x;

    for (int i = 0; i < n; i++)    {

        if (pre == p[i].x) {
            if (tmp == p[i].score)
                vec.insert(i);
            else if (tmp > p[i].score) {
                vec.clear();
                vec.insert(i);
                tmp = p[i].score;
            }
        } else {

            if (ans <= tmp) {
                if (ans < tmp)
                    score.clear();
                add_ans(tmp);
            }
            ans = max (ans, tmp);
            tmp = p[i].score;
            pre = p[i].x;
            vec.clear();
            vec.insert(i);
        }
    }

    if (ans <= tmp) {
        if (ans < tmp)
            score.clear();
        add_ans(tmp);
    }
    ans = max (ans, tmp);

    printf("Stan: %d; Ollie:", ans);
    for (set<int>::iterator it = score.begin(); it != score.end(); it++)
        printf(" %d", *it);
    printf(";\n");
}

int main () {

    while (scanf ("%d", &n) && n) {
        solve();
    }
    return 0;
}
时间: 2024-10-11 01:26:24

UVA10869 - Brownie Points II(线段树)的相关文章

UVA 10869 - Brownie Points II(树状数组+离散化)

题目链接:点击打开链接 思路:统计区间和, 我们想到了树状数组, 离散化后, 枚举第一个人选取的x坐标, 用两个树状数组,以y坐标为下标建树, 一个表示当前左边的情况, 一个表示右边的情况, 再枚举当前垂直线上的每个点, 可以用树状数组快速统计结果, 该题题意挺难理解的, 要求输出第一个人的最小得分的最大值ans, 还有就是当第一个人取ans时第二个人的可能得分.时间复杂度O(nlogn) 细节参见代码: #include <cstdio> #include <cstring> #

UVA 10869 - Brownie Points II(树状数组)

UVA 10869 - Brownie Points II 题目链接 题意:平面上n个点,两个人,第一个人先选一条经过点的垂直x轴的线,然后另一个人在这条线上穿过的点选一点作垂直该直线的线,然后划分出4个象限,第一个人得到分数为1,3象限,第二个人为二四象限,问第一个个人按最优取法,能得到最小分数的最大值,和这个值下另一个人的得分可能情况 思路:树状数组,可以枚举一点,如果能求出右上和左下点的个数就好办了,其实用一个树状数组,把y坐标离散化掉,然后记录进来,然后把点按x从左往右,每次删掉点后查询

POJ 2464 Brownie Points II 树状数组+扫描线

题意奇葩的一笔,本质上就是一个复杂统计,智商低下的我想不出来只好去搜了题解 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <string> #include <queue> #include <deque> #inclu

UVA 10869 - Brownie Points II(树阵)

UVA 10869 - Brownie Points II 题目链接 题意:平面上n个点,两个人,第一个人先选一条经过点的垂直x轴的线.然后还有一个人在这条线上穿过的点选一点作垂直该直线的线,然后划分出4个象限,第一个人得到分数为1.3象限,第二个人为二四象限.问第一个个人按最优取法,能得到最小分数的最大值,和这个值下还有一个人的得分可能情况 思路:树状数组,能够枚举一点,假设能求出右上和左下点的个数就好办了,其有用一个树状数组,把y坐标离散化掉,然后记录进来,然后把点按x从左往右,每次删掉点后

poj 2464 Brownie Points II(扫描线)

题目链接:poj 2464 Brownie Points II 题意: 题意很迷啊. 有一些点,Stan选择某个点,经过这个点画一条竖线,Ollie选择一个经过这条直接的点画了条横线. Stan选一,三象限的点,Ollie选二.四象限的点. Stan的策略是,自己画一条竖线之后,Ollie有很多种选择,在所有选择中,Stan能获得数目的最小值的最大值,而Ollie的选择便 是让自己越多越好. 题解: 下面是cxlove dalao的题解: 首先对于某个方向离散化,我是按x排序,将y离散化. 建立

FZU Problem 2171 防守阵地 II (线段树,区间更新)

 Problem 2171 防守阵地 II Accept: 143    Submit: 565Time Limit: 3000 mSec    Memory Limit : 32768 KB  Problem Description 部队中总共有N个士兵,每个士兵有各自的能力指数Xi,在一次演练中,指挥部确定了M个需要防守的地点,指挥部将选择M个士兵依次进入指定地点进行防守任务,获得的参考指数即为M个士兵的能力之和.随着时间的推移,指挥部将下达Q个指令来替换M个进行防守的士兵们,每个参加完防守

FZU2171 防守阵地 II (线段树)

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2170 贴个baka爷的代码留念.. 数据出的有问题,输入的字符串长度不超过1000 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #incl

LightOJ 1089 - Points in Segments (II) 线段树区间修改+离散化

http://www.lightoj.com/volume_showproblem.php?problem=1089 题意:给出许多区间,查询某个点所在的区间个数 思路:线段树,由于给出的是区间,查询的是点,考虑将其离线并离散化,普通线段树即可. /** @Date : 2016-12-17-20.49 * @Author : Lweleth ([email protected]) * @Link : https://github.com/ * @Version : */ #include<bi

bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 145  Solved: 76[Submit][Status][Discuss] Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,