Codeforces Beta Round #12 (Div 2 Only)D Ball(树状数组的新应用)

D. Ball
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

N ladies attend the ball in the King's palace. Every lady can be described with three values: beauty, intellect and richness. King's Master of Ceremonies knows that ladies are very special creatures. If some lady understands that there is other lady at the ball which is more beautiful, smarter and more rich, she can jump out of the window. He knows values of all ladies and wants to find out how many probable self-murderers will be on the ball. Lets denote beauty of the i-th lady by Bi, her intellect by Ii and her richness by Ri. Then i-th lady is a probable self-murderer if there is some j-th lady that Bi < Bj, Ii < Ij, Ri < Rj. Find the number of probable self-murderers.

Input

The first line contains one integer N (1 ≤ N ≤ 500000). The second line contains N integer numbers Bi, separated by single spaces. The third and the fourth lines contain sequences Ii and Ri in the same format. It is guaranteed that 0 ≤ Bi, Ii, Ri ≤ 109.

Output

Output the answer to the problem.

Sample test(s)
input
3
1 4 2
4 3 2
2 5 3
output
1

http://codeforces.com/problemset/problem/12/D

题意是:有n个女士去参加舞会,每人有r,c,b三个属性,如果有比她每个属性值都大的人存在,她就跳楼(这人真想不开。。。)。给出n个人的属性,问有多少人跳楼。


思路:通过排序确定某个属性的大小关系,再通过树状数组或者线段树,统计。做法,先对任意一个属性从大到小排序(比如b),这个属性值相等情况下属性r从小到大排序,因为只有都大于的情况下才跳楼,这样即使在b相等情况下也不会错误统计结果。接下来的做法很巧妙,我是看了一天终于看懂了cf里面的那个代码。对属性r离散化,规则是找出r最大的标号1,依次类推,不是最小的标号1。为什么要这样呢。这一树状数组的应用是把r当作坐标,把c值当作权值,每个元素tree[i]代表前i个元素里面最大的权值是多少,这样按照排好序的数组扫描,首先看看bi之前是否有比他小的,即b值比他大的数,然后比较这个值是否比当前ci的值大。大的话就符合了每个属性都大于第i个人,那么跳。。。。然后向上更新最大值。好短的代码。。。。而且比赛时候写的,Orz。。。自己需要多训练。需要注意的是,这组代码里面的逆序离散化不是连续自然数,有充分属性b的情况下会断续,这并不影响结果,因为是要找之前有没有,只要相对的大小关系没有改变就可以。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define rep(i,a) for(int i = 0;i < a;i ++)
using namespace std;
const int N = 500010;
struct node
{
	int x, y, z;
}rec[N];
bool operator < (node a,node b)
{
	return a.x != b.x?a.x > b.x:a.y < b.y;
}
int h[N];//用于离散化的数组,同时后面用作树状数组
int main(){
	int n;
	cin >> n;
	rep(i,n)cin >> rec[i].x;
	rep(i,n)cin >> rec[i].y,h[i] = rec[i].y;
	rep(i,n)cin >> rec[i].z;
	sort(h, h + n);
	sort(rec,rec + n);
	rep(i,n)rec[i].y = n - (lower_bound(h,h + n,rec[i].y) - h);
	
	memset(h,128,sizeof(h));
	int ans = 0;
	rep(i,n)
	{
		int tmp = -0x7fffffff;
		for(int j = rec[i].y - 1;j; j -= j & -j)tmp = max(tmp, h[j]);
			if(tmp > rec[i].z)ans ++;//符合要求结果加一
		for(int j = rec[i].y;j <= n;j += j & -j)h[j] = max(h[j],rec[i].z);
	}
	cout<<ans<<endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值