线段树是一类非常有用的数据结构 这个可以体现到求解一组序列的逆序数上来
可以这么想 我们求逆序数的时候,对于每一个数字都找前面比他大的数字的数目
例如 9 5 7 9这三个序列 我们先找5前面比5大的数字的个数 很明显是9 有一个
我们继续找7前面比7大的个数 也是9
找 9 前面比9大的个数 和明显没有
按照这个想法实现的是O(n^2)的一个算法 复杂度不是很好
既然是区间操作 我们想到了线段树
我们先建立一个空树 然后呢 按照这个序列的顺序将每个值插入 ,每次插入伴随一次查询 查询前面插入的比这次插入的大的数字的个数
然后就可以了 复杂度 nlogn 可以接受
需要注意 :1.很多时候可能要离散化 这个很容易想 因为如果数字是long long 类型以及以上的那么空间就爆了
2.注意建立空树的时候要在 1-n+1上建立空树 因为有可能查询n query(1,n+1,n)的时候就出错了 这样并不影响结果,仔细体会一下
下面这是没有离散的代码
#include
#include
#include
using namespace std;
const int maxn = 1e5+10;
int arr[maxn];
struct node{int sum,l,r;};
node segtree[4*maxn];
int fa[maxn];
void buildtree(int num,int l,int r)
{
if(l==r)
{
segtree[num].l=segtree[num].r=l;
fa[r]=num;
segtree[num].sum=0;
return ;
}
segtree[num].l=l;
segtree[num].r=r;
segtree[num].sum=0;
int mid=(l+r)/2;
buildtree(2*num,l,mid);
buildtree(2*num+1,mid+1,r);
}
int query(int num,int l,int r)
{
if(segtree[num].l==l&&segtree[num].r==r)
{
return segtree[num].sum;
}
int mid=(segtree[num].l+segtree[num].r)/2;
if(l>mid)
{
return query(2*num+1,l,r);
}
else if(r<=mid)
{
return query(2*num,l,r);
}
else
{
return query(2*num,l,mid)+query(2*num+1,mid+1,r);
}
}
void update(int num,int x)
{
if(segtree[num].l==segtree[num].r)
{
segtree[num].sum++;
return ;
}
int mid=(segtree[num].l+segtree[num].r)/2;
if(x<=mid)
update(2*num,x);
else update(2*num+1,x);
segtree[num].sum++;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>arr[i];
buildtree(1,1,n+1);
int sum=0;
for(int i=1;i<=n;i++)
{
sum+=query(1,arr[i]+1,n+1);
update(1,arr[i]);
}
cout<
下面是离散化方式 :
#include
#include
#include
using namespace std;
int arr[1000];
int save[1000];
vector v;
int getid(int x) { return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>arr[i];
v.push_back(arr[i]);
}
sort(v.begin(),v.end()),unique(v.begin(),v.end());
for(int i=1;i<=n;i++)
save[i]=getid(arr[i]);
return 0;
}
但是用了stl很容易t所以离散化尽量自己做 下面是进行离散化 线段树求逆序操作
#include
#include
#include
#include
#include
#include
#include
#include
#include
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define inf 1e9+7
int arr[1100200];
int brr[1100200];
int hashh[1100200];
int save[1100200];
int sum[3300200];
vector q;
int n,m;
void update(int num,int l,int r,int x)
{
if(l==r) {sum[num]++;return;}
int mid=(l+r)>>1;
if(x<=mid) update(num<<1,l,mid,x);
else if(x>mid) update((num<<1)|1,mid+1,r,x);
sum[num]++;
}
int query(int num,int l,int r,int left,int right)
{
if(l==left&&r==right) return sum[num];
int mid=(l+r)>>1;
if(right<=mid) return query(num<<1,l,mid,left,right);
else if(left>mid) return query((num<<1)|1,mid+1,r,left,right);
else return query(num<<1,l,mid,left,mid)+query((num<<1)|1,mid+1,r,mid+1,right);
}
int getid(int x) {return lower_bound(save+1,save+m+1,x)-save;}
int main()
{
while(scanf("%d",&n)!=EOF&&n){
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
scanf("%d",&arr[i]);
hashh[i]=arr[i];
}
sort(hashh+1,hashh+n+1);
m=1;save[1]=hashh[1];
for(int i=2;i<=n;i++) if(hashh[i]!=hashh[i-1]) save[++m]=hashh[i];
int size=m;
for(int i=1;i<=n;i++) brr[i]=getid(arr[i]);
long long cnt=0;
for(int i=1;i<=n;i++)
{
update(1,1,size+10,brr[i]);
cnt+=(long long)query(1,1,size+10,brr[i]+1,size+10);
}
cout<