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
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.
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 ).
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.
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
1
6
7
题意:给出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); } |
lowbit()的返回值就是 2^k 次方的值。
求出来 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=n-lowbit(n); } return sum; } |
(三)当数组中的元素有变更时,树状数组就发挥它的优势了,算法如下(修改为给某个节点 i 加上 x ):
(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);
}
}