以前只学了归并求逆序对,这里学下树状数组求逆序对
--------------------------------
题意:这里看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;
}