AcWing.241. 楼兰图腾(树状数组+逆序对变形)

以前只学了归并求逆序对,这里学下树状数组求逆序对

--------------------------------

题意:这里看https://www.acwing.com/problem/content/description/243/

题解:处理每一位左边所有比他小的/比他大的,右边比他小的/比他大的 , 在枚举每一位a[i],来找 ^ 和 v.

          这里用树状数组求左边所有比他小的/比他大的,右边比他小的/比他大

         查询/维护都是O(logn);

          逆序遍历a[]数组,这样“已经出现的数”就是在a[i]后边的数,用树状数组查询的内容就是"每个a[i]后边有多少比他小/大的"

          正序遍历a[]数组,这样“已经出现的数”就是在a[i]前边的数,用树状数组查询的内容就是“每个a[i]前面有多少比他小/大的”

细节:脑子抽了,离散化了(n=2e5),多了一个排序的复杂的,就T了,其实不用离散化、就可以了

         其实当数据特别大求逆序对还是直接归并比较好。

#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<vector> 
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
typedef long long ll;
int a[maxn];int c[maxn];
ll Lb[maxn];//左边比他大的 
ll Rb[maxn]; //右边比他大的 
ll Ls[maxn];//左边比他小的
ll Rs[maxn];//右边比他小的 
int n;
vector<int> v;
int lowbit(int x) {
      return x&-x; 
}
void add(int id, int p){//处理的是下标 
    while(id <= n){
        c[id] += p;
        id += lowbit(id);
    }
}
int getsum(int id){//求前I项的和 
    int ans = 0;
    while(id >= 1){
        ans += c[id];
        id -= lowbit(id);
    }
    return ans;
}
int get_id(int x){
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int main(){
	    std::ios::sync_with_stdio(false);  
	    cin>>n;
		v.clear();
		for(int i=1;i<=n;i++){
			cin>>a[i];
			c[i]=0;
		//	v.push_back(a[i]);
		}
	//	sort(v.begin(),v.end());
		for(int i=1;i<=n;i++){//前面有几个比他大的 
			Lb[i]=getsum(n)-getsum(a[i]);
			add(a[i],1);
		}
		for(int i=1;i<=n;i++) c[i]=0;
		for(int i=n;i>=1;i--){//后面有几个比他大的 
			Rb[i]=getsum(n)-getsum(a[i]);
			add(a[i],1);
		}
        for(int i=1;i<=n;i++) c[i]=0;
        for(int i=1;i<=n;i++){//前面有几个比他小的 
			Ls[i]=getsum(a[i]);
			add(a[i],1);
		}
		for(int i=1;i<=n;i++) c[i]=0;
		for(int i=n;i>=1;i--){//后面有几个比他小的 
			Rs[i]=getsum(a[i]);
			add(a[i],1);
		}
        ll ans1=0; ll ans2=0;
        for(int i=1;i<=n;i++){
        	ans1+=Lb[i]*Rb[i];
        	ans2+=Ls[i]*Rs[i];
		}
		cout<<ans1<<" "<<ans2<<endl;
	return 0;
} 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值