1010 Lehmer Code (35 分)

树状数组

题意

  • 给出一个数组,求每个位置上的值,在其右边有多少个比它小的值。

注意

  • 数组中没有重复元素。我的原版本中有个小bug,有重复元素的时候,编号应该是A[E[i].pos] = A[E[i-1].pos];
  • 树状数组从1开始编号

思路

  • 因为不知道数值的范围,所以先将数组中的元素离散化。即将其映射到1到1e5的范围内,A数组是原下标映射成的新下标。比如有数组{ 24, 35, 12, 1, 56, 23 },最后一个元素23,下标是i = 5,离散化后下标是A[5] = 3
  • 直接套树状数组的模板

原版本

#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1e5+7;
#define low(x) ((x)&(-x))
int n, x;
struct Node{
	int val; //原始值 
	int pos; //原始序号 
	bool operator <(const Node& a) const{
		return val < a.val;
	} 
}E[N];

int A[N], c[N], res[N];
void update(int x, int v){
	while(x <= n){
		c[x] += v;
		x += low(x);
	}
}
int sum(int x){
	int sumx = 0;
	while(x){
		sumx += c[x];
		x -= low(x);
	}
	return sumx;
}
int main(){
	
	cin>>n;
	for(int i = 0; i < n; i++){
		cin>>E[i].val;
		E[i].pos = i;  //原始序号 
	}
	sort(E, E+n); //按值排序 
	for(int i = 0; i < n; i++){
		if(!i || E[i-1].val != E[i].val){
			A[E[i].pos] = i + 1; //树状数组必须从1开始 只是相对顺序 
		}else{
			A[E[i].pos] = E[i-1].pos; //如果相等说明相对大小一致 直接继承前面的大小 
		} 
	} 
	
	//更新获得树状数组
	//使用hash获得比A[i]小的个数
	for(int i = n - 1 ; i >= 0; i--){
		update(A[i], 1); //原始下标为n-1的数值的相对大小为A[i] 
		res[i] = sum(A[i] - 1); //找到hash[A[i]-1] +  hash[A[i]-2]+ ... + hash[2] + hash[1] 前缀和 
	} 
	for(int i = 0 ; i < n; i++){
		if(i) cout<<" ";
		cout<<res[i];
	} 
	return 0;
} 

新版

#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1e5+7;
#define low(x) ((x)&(-x))
int n, x;
struct Node{
	int val; //原始值 
	int pos; //原始序号 
	bool operator <(const Node& a) const{
		return val < a.val;
	} 
}E[N];

int A[N], c[N], res[N];
void update(int x, int v){
	while(x <= n){
		c[x] += v;
		x += low(x);
	}
}
int sum(int x){
	int sumx = 0;
	while(x){
		sumx += c[x];
		x -= low(x);
	}
	return sumx;
}
int main(){
	
	cin>>n;
	for(int i = 0; i < n; i++){
		cin>>E[i].val;
		E[i].pos = i;  //原始序号 
	}
	sort(E, E+n); //按值排序 
	for(int i = 0; i < n; i++){
        if(!i || E[i].val == E[i-1].val)
		    A[E[i].pos] = i + 1; //树状数组必须从1开始 只是相对顺序 
        else{
            A[E[i].pos] = A[E[i-1].pos];
        }
	} 
	
	//更新获得树状数组
	//使用hash获得比A[i]小的个数
	for(int i = n - 1 ; i >= 0; i--){
		update(A[i], 1); //原始下标为n-1的数值的相对大小为A[i] 
		res[i] = sum(A[i] - 1); //找到hash[A[i]-1] +  hash[A[i]-2]+ ... + hash[2] + hash[1] 前缀和 
	} 
	for(int i = 0 ; i < n; i++){
		if(i) cout<<" ";
		cout<<res[i];
	} 
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值