洛谷P1428-小鱼比可爱(树状数组)
一、题目描述
人比人,气死人;鱼比鱼,难死鱼。小鱼最近参加了一个“比可爱”比赛,比的是每只鱼的可爱程度。参赛的鱼被从左到右排成一排,头都朝向左边,然后每只鱼会得到一个整数数值,表示这只鱼的可爱程度,很显然整数越大,表示这只鱼越可爱,而且任意两只鱼的可爱程度可能一样。由于所有的鱼头都朝向左边,所以每只鱼只能看见在它左边的鱼的可爱程度,它们心里都在计算,在自己的眼力范围内有多少只鱼不如自己可爱呢。请你帮这些可爱但是鱼脑不够用的小鱼们计算一下。
- 输入格式
第一行输入一个整数n,表示鱼的数目。
第二行内输入 n 个整数,用空格间隔,依次表示从左到右每只小鱼的可爱程度。
- 输出格式
行内输出 n 个整数,用空格间隔,依次表示每只小鱼眼中有多少只鱼不如自己可爱。
- 输入输出样例
输入
6
4 3 0 5 1 2
**输出 **
0 0 0 3 1 2
- 说明/提示
对于 100% 的数据,n≤100。
二、题目解析
-
第一种解法
暴力枚举即可。
-
第二种解法
使用树状数组,树状数组中记录小鱼可爱程度值的个数(例如题中4出现几次,3出现几次),我们重头开始遍历,每遍历一个数据更新一次树状数组即可动态求出前面比其小的值的个数。例如遍历4,4的前缀和(getsum操作)为零,更新树状数组tree[4]++;遍历3,0与其相同,此时tree[4]=1,tree[3]=1,tree[2]=0,tree[1]=0,tree[0]=1,当遍历数据5时,前五项的前缀和=3即为所求。
-
树状数组具体内容可看树状数组
三、代码实现
- 暴力枚举
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n;
int a[101],count[101]={0};
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
for(int j=i;j>=0;j--){
if(a[i]>a[j]){
count[i]++;
}
}
}
for(int i=0;i<n;i++){
cout<<count[i]<<" ";
}
return 0;
}
- 树状数组
#include<iostream>
#include<algorithm>
using namespace std;
struct stu{
int data,num;
}fish[105];
int tree[1005];//树状数组
int n;//鱼的个数,总数n
bool cmp(stu a,stu b){
return a.data<b.data;
}
bool cmp1(stu a,stu b){
return a.num<b.num;
}
int lowbit(int x){
return x&-x;
}
void add(int k,int x){
while (k<=n)
{
tree[k]+=x;
k+=lowbit(k);
}
}
int getsum(int k){
int ans=0;
while (k>0)
{
ans+=tree[k];
k-=lowbit(k);
}
return ans;
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>fish[i].data;
fish[i].num=i;
}
sort(fish,fish+n,cmp);
for(int i=0;i<n;i++){
fish[i].data=i;
}
sort(fish,fish+n,cmp1);
for(int i=0;i<n;i++){
cout<<getsum(fish[i].data+1)<<" ";//+1使访问位置不出现0,因为我们使用的树状数组是1~n(getsum操作中k>0)
add(fish[i].data+1,1);//整体数据向后移动一位,对结果以及性能基本上不产生影响。
}
return 0;
}