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

UVA 10869 - Brownie Points II

题目链接

题意:平面上n个点,两个人,第一个人先选一条经过点的垂直x轴的线,然后另一个人在这条线上穿过的点选一点作垂直该直线的线,然后划分出4个象限,第一个人得到分数为1,3象限,第二个人为二四象限,问第一个个人按最优取法,能得到最小分数的最大值,和这个值下另一个人的得分可能情况

思路:树状数组,可以枚举一点,如果能求出右上和左下点的个数就好办了,其实用一个树状数组,把y坐标离散化掉,然后记录进来,然后把点按x从左往右,每次删掉点后查询当前高度向上的点的个数,这样就能得到右上角点的个数,同理也能求左下角,能处理这步就好办了,最后注意答案要取重并且递增,用set就ok了

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;

#define lowbit(x) (x&(-x))

const int N = 200005;

struct Point {
    int x, y, rank, ans, Mi;
    int xn, yn;
} p[N];

int bit[N];
set<int> out;

void add(int x, int v) {
    while (x < N) {
	bit[x] += v;
	x += lowbit(x);
    }
}

int get(int x) {
    int ans = 0;
    while (x > 0) {
	ans += bit[x];
	x -= lowbit(x);
    }
    return ans;
}

int get(int l, int r) {
    return get(r) - get(l - 1);
}

bool cmpy(Point a, Point b) {
    return a.y < b.y;
}

bool cmpx(Point a, Point b) {
    if (a.x == b.x) return a.y > b.y;
    return a.x < b.x;
}

bool cmpx2(Point a, Point b) {
    if (a.x == b.x) return a.y < b.y;
    return a.x > b.x;
}

int n, top;

void init() {
    memset(bit, 0, sizeof(bit));
    for (int i = 0; i < n; i++) {
	scanf("%d%d", &p[i].x, &p[i].y);
	p[i].ans = 0;
	p[i].xn = p[i].yn = 0;
    }
    sort(p, p + n, cmpy);
}

void solve() {
    top = 1;
    for (int i = 0; i < n; i++) {
	if (i && p[i].y != p[i - 1].y)
	    top++;
	p[i].rank = top;
	add(p[i].rank, 1);
    }
    for (int i = 0; i < n; i++) {
	int j;
	int len = 0;
	for (j = i; p[i].y == p[j].y && j < n; j++)
	    len++;
	for (j = i; p[i].y == p[j].y && j < n; j++)
	    p[j].yn = len;
	i = j - 1;
    }
    sort(p, p + n, cmpx);
    for (int i = 0; i < n; i++) {
	add(p[i].rank, -1);
	p[i].ans += get(p[i].rank + 1, top);
    }
    for (int i = 0; i < n; i++) {
	int j;
	int len = 0;
	for (j = i; p[i].x == p[j].x && j < n; j++)
	    len++;
	for (j = i; p[i].x == p[j].x && j < n; j++)
	    p[j].xn = len;
	i = j - 1;
    }
    memset(bit, 0, sizeof(bit));
    for (int i = 0; i < n; i++)
	add(p[i].rank, 1);
    sort(p, p + n, cmpx2);
    for (int i = 0; i < n; i++) {
	add(p[i].rank, -1);
	p[i].ans += get(1, p[i].rank - 1);
    }
    for (int i = 0; i < n; i++) {
	int j;
	int Min = 1000000000;
	for (j = i; p[i].x == p[j].x && j < n; j++)
	    Min = min(Min, p[j].ans);
	for (j = i; p[i].x == p[j].x && j < n; j++)
	    p[j].Mi = Min;
	i = j - 1;
    }
    int Max = 0;
    out.clear();
    for (int i = 0; i < n; i++) {
	if (p[i].Mi != p[i].ans) continue;
	if (p[i].ans > Max) {
	    Max = p[i].ans;
	    out.clear();
	    out.insert(n - p[i].ans - p[i].xn - p[i].yn + 1);
	}
	else if (p[i].ans == Max) {
	    out.insert(n - p[i].ans - p[i].xn - p[i].yn + 1);
	}
    }
    printf("Stan: %d; Ollie:", Max);
    for (set<int>::iterator it = out.begin(); it != out.end(); it++)
	printf(" %d", *it);
    printf(";\n");
}

int main() {
    while (~scanf("%d", &n) && n) {
	init();
	solve();
    }
    return 0;
}

UVA 10869 - Brownie Points II(树状数组),布布扣,bubuko.com

时间: 2024-12-25 23:00:43

UVA 10869 - Brownie Points II(树状数组)的相关文章

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从左往右,每次删掉点后

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

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

HDOJ 5147 Sequence II 树状数组

树状数组: 维护每一个数前面比它小的数的个数,和这个数后面比他大的数的个数 再枚举每个位置组合一下 Sequence II Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 121    Accepted Submission(s): 58 Problem Description Long long ago, there is a seq

hdu 5147 Sequence II (树状数组 求逆序数)

题目链接 Sequence II Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 331    Accepted Submission(s): 151 Problem Description Long long ago, there is a sequence A with length n. All numbers in this se

UVA 1513 Movie collection (树状数组+反向存储)

题意:给你n盘歌碟按照(1....n)从上到下放,接着m个询问,每一次拿出x碟,输出x上方有多少碟并将此碟放到开头 直接想其实就是一线段的区间更新,单点求值,但是根据题意我们可以这样想 首先我们倒着存  n--1,接着每次询问时把放碟子放到最后,这样我们要开一个映射数组映射每个碟子在哪个位置 其中我们需要使用树状数组维护每个绝对位置是否有碟子(有些碟子已经放到了后面了),再使用区间求和就好了 #include<set> #include<map> #include<queue

UVA 1513 - Movie collection(树状数组)

题目链接:点击打开链接 题意: 有编号1~n的n个影碟从上到下排列, 每次取一个影碟并把其放在最上面, 求每次取之前该影碟前面有多少个影碟. 取出影碟, 将该位置-1即可, 容易想到用树状数组来维护, 但是还要放到最前面. 其实解决方法很简单, 就是把数组开大一点, 前面留出足够大的空间, 不断更新位置即可. 细节参见代码: #include<cstdio> #include<cstring> #include<algorithm> #include<iostre

hdu5147 Sequence II树状数组求逆序对

//用树状数组求出在b前面比b小的数的个数 //然后求b后面的顺序对的个数, //枚举b可得quad //由于数列是从1到n的所有数 //那么(n-num[j])-(j-1-totol[j])即为第j个数之后比j大的数的个数 //其中num[j]表示第j个数,total[j]表示在j之前比j小的数的个数 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int

HDU 5147 Sequence II 树状数组水题

无聊咯,学某y,水一发 给你n个数的排列,A[1]到A[n],统计多少四元组(a,b,c,d)满足,1<=a<b<c<d<=n,且A[a]<A[b],A[c]<A[d] 树状数组统计前缀和咯 1 #include<cstdio> 2 #include<cstring> 3 #include<cctype> 4 typedef long long ll; 5 const int maxn=5e4+10; 6 int T,n,a[m