Car race game 树状数组
2016-03-13 22:29
183 查看
Car race game
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 12 Accepted Submission(s): 5
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.
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 i-th racer's Starting point coordinate, Vi means
the i-th 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
Source
2011 Heilongjiang collegiate PC
题意:给出n个点你,点代表车,每个点有两个数据 一个是速度一个是出发位置,每台车匀速运动,求发生超车的次数。
思路:根据出发位置从小到大排序,如果出发位置相同,那么按照速度从小到大排序,那么只要枚举一次,每次计算速度小于
f[i].v的车辆有多少个就好,为了优化求和速度,用树状数组去保存数据。
下面转载一篇描写树状数组文章 文章转自http://www.cnblogs.com/zhangshu/archive/2011/08/16/2141396.html
昨天学了一下树状数组,随笔都写了一大半,结果一个不小心就把他给删了,哎。。。。。。今天就当是复习吧!再写一次。
如果给定一个数组,要你求里面所有数的和,一般都会想到累加。但是当那个数组很大的时候,累加就显得太耗时了,时间复杂度为O(n),并且采用累加的方法还有一个局限,那就是,当修改掉数组中的元素后,仍然要你求数组中某段元素的和,就显得麻烦了。所以我们就要用到树状数组,他的时间复杂度为O(lgn),相比之下就快得多。下面就讲一下什么是树状数组:
一般讲到树状数组都会少不了下面这个图:
下面来分析一下上面那个图看能得出什么规律:
据图可知:c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4,c5=a5,c6=a5+a6,c7=a7,c8=a1+a2+a3+a4+a5+a6+a7+a8,c9=a9,c10=a9+a10,c11=a11........c16=a1+a2+a3+a4+a5+.......+a16。
分析上面的几组式子可知,当 i 为奇数时,ci=ai ;当 i 为偶数时,就要看 i 的因子中最多有二的多少次幂,例如,6 的因子中有 2 的一次幂,等于 2 ,所以 c6=a5+a6(由六向前数两个数的和),4 的因子中有 2 的两次幂,等于 4 ,所以 c4=a1+a2+a3+a4(由四向前数四个数的和)。
(一)有公式:cn=a(n-a^k+1)+.........+an(其中 k 为 n 的二进制表示中从右往左数的 0 的个数)。
那么,如何求 a^k 呢?求法如下:
int lowbit(int x) { return x&(-x); } |
求出来 2^k 之后,数组 c 的值就都出来了,接下来我们要求数组中所有元素的和。
(二)求数组的和的算法如下:
(1)首先,令sum=0,转向第二步;
(2)接下来判断,如果 n>0 的话,就令sum=sum+cn转向第三步,否则的话,终止算法,返回 sum 的值;
(3)n=n - lowbit(n)(将n的二进制表示的最后一个零删掉),回第二步。
代码实现:
int Sum(int n) { int sum=0; while(n>0) { sum+=c ; n=n-lowbit(n); } return sum; } |
(1)当 i<=n 时,执行下一步;否则的话,算法结束;
(2)ci=ci+x ,i=i+lowbit(i)(在 i 的二进制表示的最后加零),返回第一步。
代码实现:
void change(int i,int x) { while(i<=n) { c[i]=c[i]+x; i=i+lowbit(i); } } |
有关于lowbit的理解,可以手动算一下。
下面附上代码
#include<bits/stdc++.h>
using namespace std;
struct node
{
int x,v;
}f[100005];
int p[100005];
int in[1000009];
int kos;
int lowbit(int x)
{
return x&(-x);
}
int sum(int en) //求和
{
int tt=0;
while(en>0)
{
tt+=in[en];
en-=lowbit(en);
}
return tt;
}
void add(int pos,int num) //in[pos]加上num
{
if(pos==0)return;
while(pos<=kos)
{
in[pos]+=num;
pos+=lowbit(pos);
}
}
int blook(int l,int r,int num)//二分查找,用于离散化
{
int mid=(l+r)/2;
while(l<=r)
{
if(p[mid]==num)
return mid+1;
else if(p[mid]<num) l=mid+1;
else if(p[mid]>num) r=mid-1;
mid=(l+r)/2;
}
return -1;
}
int cmp(node a,node b)
{
if(a.x!=b.x)return a.x>b.x;
else return a.v<b.v;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
{
scanf("%d %d",&f[i].x,&f[i].v);
p[i]=f[i].v;
}
sort(p,p+n);
int pnum=0;
for(int i=1;i<n;i++)
{
if(p[i]!=p[pnum])
p[++pnum]=p[i];
}
kos=pnum+1;
for(int i=0;i<n;i++)
{
f[i].v=blook(0,pnum,f[i].v);//记录下标更利于接下来的操作
}//上面是离散化操作,避免数据过大造成的无法储存。
sort(f,f+n,cmp);
memset(in,0,sizeof(in));
long long ans=0;
for(int i=0;i<n;i++)
{
ans+=sum(f[i].v-1);//求速度小于f[i].v的车辆总和。
add(f[i].v,1);//在树状数组中加入该车。
}
printf("%lld\n",ans);
}
}
相关文章推荐
- UVA10020用最少的线段去覆盖给定的线段
- 引用路径 ../ ./ 说明
- BOM
- 【机器学习详解】线性回归、梯度下降、最小二乘的几何和概率解释
- swift 之xib自定义view可视化到storyboard
- 123
- UI自定义进度条控件
- 从start_kernel到init
- Java微信支付之公众号支付、扫码支付
- 文件存储格式转换(ASCII <-> UTF-8)
- Windows静态库和动态库的创建和使用
- Linux内核分析第三周
- C++第一次使用
- 顺序表的几种实现
- 粗谈《Java与模式》一书
- Unity3D 5 官方教程:标准着色器:内容和环境;金属与镜面工作流
- 设计模式(三)
- OpenGL+VS2010+Win7配置简记
- JVM字节码指令集简介
- java day02 交换数据