WUSTOJ 1337: Car race game(C)树状数组,离散化

80 篇文章 18 订阅
36 篇文章 0 订阅

题目链接:1337: Car race game
参考资料:⑴ Car race game 树状数组 棋煜⑵ 树状数组⑶ 离散化
补充资料:⑴ qsort⑵ 二分查找

Description

Bob is a game programming specialist. In his new car race game, there are some racers(n means the amount of racers (1<=n<=100000)) racers star from someplace(xi means Starting point coordinate),and they possible have different speed(V means speed).so it possibly takes place to overtake(include staring the same point ). now he want to calculate the maximal amount of overtaking.

有 n 名参赛者,每名参赛者从自己的位置(Xi)以速度(Vi)匀速运动,问最后有多少次超越?

Input

The first line of the input contains an integer n-determining the number of racers. Next n lines follow, each line contains two integer Xi and Vi.(xi means the ith racer’s Starting point coordinate, Vi means the ith racer’s speed.0<Xi, Vi<1000000).

Output

For each data set in the input print on a separate line, on the standard output, the integer that represents the maximal amount of overtaking.

Sample Input

2
2 1
2 2
5
2 6
9 4
3 1
4 9
9 1
7
5 5
6 10
5 6
3 10
9 10
9 5
2 2

Sample Output

1
6
7

分析?

数据规模已经达到 100000,用普通做法:先输入,按位置升序,比较速度,个数加1,,这种双循环是会超时的。

更好的思路是采用树状数组离散化来处理此题。相信看完百科,大家对这两个算法都有所了解。

以Simple Input的第3组数据为例说明:

  • racer[]如下:
i0123456
racer[i].x5653992
racer[i].v5106101052
  • 构造新速度speed[],i 就是新速度,如下:
i1234
speed[i]25610
  • 离散化后,racer[]如下:
i0123456
racer[i].x5653992
racer[i].v2434421
  • 树状数组tree[]保存的是对应区间的速度的人数。
itree[i]
1A1
2A1+A2
3A3
4A1+A2+A3+A4

这里的A[]保存的是每种速度的已添加的人数,在代码中A[]并不需要,只要tree[]即可。

  • 参赛者排序是为了保证每名参赛者只能超越自己前面的速度比自己小的人。否则树状数组就没意义了。
  • 注意,最坏的情况是每个人都能超越他前面的,那么ans最大为 99999+99998+L+2+1=4999950000,超过了int的范围,所以结果应该使用long long

C代码?

/*******************************************************************************
	Problem:	1337
	Language:	C
	Result:		Accepted
	Time:		629ms
	Memory:		3432 kb
	Author:		wowpH
	Version:	2.0
	Date:		2019-7-1 17:05:14
*******************************************************************************/
#include<stdio.h>
#include<stdlib.h>										//qsort()头文件
#include<memory.h>										//memset()头文件

int numberOfRacers;										//参赛者人数

int speed[100001];										//速度,下标从1开始
int speedNum = 0;										//数组speed不重复数据个数

int tree[100001];										//树状数组,下标从1开始

typedef struct node {
	int x, v;											//位置和速度
}Racer;													//参赛者
Racer racer[100001];

void inputRacer() {										//输入参赛者信息
	for (int i = 0; i < numberOfRacers; ++i) {
		scanf("%d %d", &racer[i].x, &racer[i].v);		//输入位置和速度
	}
}

int compareSpeed(const int* a, const int* b) {			//比较函数,速度升序排序
	return (*a) - (*b);
}

int deleteDeduplication() {								//删除重复数据
	int num = 1;										//不重复数据的个数
	for (int i = 2; i <= numberOfRacers; ++i) {
		if (speed[num] != speed[i]) {
			speed[++num] = speed[i];
		}
	}
	return num;											//返回不重复数据的个数
}

int getSpeedIndex(int key) {							//获取速度下标,二分查找
	int left, middle, right;
	left = 1;
	right = speedNum;
	while (left <= right) {
		middle = (left + right) / 2;
		if (speed[middle] == key) {						//找到
			return middle;								//返回下标
		}
		else if (speed[middle] < key) {
			left = middle + 1;
		}
		else if (speed[middle] > key) {
			right = middle - 1;
		}
	}
	return 0;											//未找到,返回0
}

void discretization() {									//离散化
	for (int i = 0; i < numberOfRacers; ++i) {
		speed[i + 1] = racer[i].v;						//保存速度
	}
	qsort(speed, numberOfRacers + 1, sizeof(int), compareSpeed);//升序排序
	speedNum = deleteDeduplication();	//去重,并获得数组speed的不重复数据的个数
	for (int i = 0; i < numberOfRacers; ++i) {
		racer[i].v = getSpeedIndex(racer[i].v);			//获取新序号(即新速度)
	}
}

int compareRacer(const Racer* a, const Racer* b) {		//参赛者排序
	if (a->x != b->x) {
		return b->x - a->x;								//位置降序
	}
	else if (a->v != b->v) {
		return a->v - b->v;								//速度升序
	}
	return 0;
}

int lowBit(int x) {										//计算2^k的值,
	return x & (-x);									//k是x二进制数末尾0的个数
}

int sum(int n) {										//计算能被超越的人数
	int count = 0;
	while (n > 0) {
		count += tree[n];
		n -= lowBit(n);									//修改为自己的兄弟
	}
	return count;										//返回被超越的人数
}

void add(int n, int x) {								//将第n个数加x
	while (n <= speedNum) {
		tree[n] += x;
		n += lowBit(n);									//修改为自己的父结点下标
	}
}

long long binaryIndexedTree() {							//树状数组操作
	memset(tree, 0, sizeof(tree));						//初始化树状数组
	long long ans = 0;									//结果
	for (int i = 0; i < numberOfRacers; ++i) {
		//加上速度比racer[i].v小的人数,也就是第i个人超越的人数
		ans += sum(racer[i].v - 1);
		add(racer[i].v, 1);							//将第i个人加到数组中,数量加1
	}
	return ans;											//返回最终超越的次数
}

int main() {
	while (EOF != scanf("%d", &numberOfRacers)) {		//输入参赛人数
		inputRacer();									//输入参赛者位置和速度
		discretization();								//离散化
		qsort(racer, numberOfRacers, sizeof(Racer), compareRacer);	//排序
		printf("%lld\n", binaryIndexedTree());			//用树状数组计算结果
	}
	return 0;
}

Java代码?待补充

其实就是懒?,想要的话就留言吧。

或者等到什么时候忘了,回来复习再用Java写吧。。。


版权声明

  1. 转载、参考、引用必须在首页添加如下文字:
    [WUSTOJ 1337: Car race game(C)树状数组,离散化—wowpH](https://blog.csdn.net/pfdvnah/article/details/94386984)
  2. 代码原创,公开引用不能删除首行注释(作者,版本号,时间等信息);
  3. 如果有疑问欢迎评论区留言,尽量解答;
  4. 如果有错误,还望大侠评论区指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值