P1908 逆序对-(树状数组)

Posted shoulinniao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1908 逆序对-(树状数组)相关的知识,希望对你有一定的参考价值。

https://www.luogu.org/problem/P1908

比较喜欢线段树,懒得用树状数组(只会套模板,位运算的精髓没有领悟到),一直没有记录树状数组代码,又得捡回来,趁这道题记录一下模板,为三维偏序cdq套树状数组铺垫一下。

解题思路:先对原数组a从大到小排序,依次添加进树状数组c里,每次求前缀和的结果就是 当前数的逆序对的个数。

例如数据:55,44,22,66,33,11

初始化树状数组c,清0;

添加66到4号位,则添加数组为 0,0,0,1,0,0; 66前没有比它大的数,逆序对个数为0,树状数组C为0,0,0,1,0,0;

添加55到1号位,则添加数组为 1,0,0,1,0,0; 55前没有比它大的数,逆序对个数为0,树状数组C为1,1,0,2,0,0;

添加44到2号位,则添加数组为 1,1,0,1,0,0; 44前有55比它大,逆序对个数为1,树状数组C为1,2,0,3,0,0

添加33到5号位,则添加数组为 1,1,0,1,1,0; 33前有55,44,66比它大,逆序对个数为3,树状数组C为1,2,0,3,1,1

添加22到3号位,则添加数组为 1,1,1,1,1,0; 22前有55,44,66比它大,逆序对个数为2,树状数组C为1,2,1,4,1,2

添加11到6号位,则添加数组为 1,1,1,1,1,1; 11前有55,44,22,66,33比它大,逆序对个数为5,树状数组C为1,2,1,4,1,2

坑:如果有相同的数,则排序时按照后面的先添加,这样就不会重复计算逆序对。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define inf 0x3f3f3f3f
const double pi=3.1415926;
using namespace std;

const int maxx=500005;
struct node

    int id;
    int val;
;
node a[maxx];///原数组
int c[maxx];///树状数组
int n;

bool cmp(node p1,node p2)

    if(p1.val==p2.val)///
        return p1.id>p2.id;
    return p1.val>p2.val;


int lowbit(int x)

    return x&(-x);


void add(int x,int val)///在x的位置添加val值

    while(x<=n+1)///x需要小于32005,否则,那些输入x=20000的大数据没办法找到左下的行星数量
    
        c[x]+=val;
        x+=lowbit(x);
    


int sum(int x)

    int res=0;
    while(x>0)
    
        res+=c[x];
        x-=lowbit(x);
    
    return res;




int main()///P1908

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i].val),a[i].id=i;
    sort(a+1,a+n+1,cmp);
    ll ans=0;
    for(int i=1;i<=n;i++)
    
        ans +=(ll)sum(a[i].id);
        add(a[i].id,1);
    
    printf("%lld\n",ans);
    return 0;

 

以上是关于P1908 逆序对-(树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

树状数组 P1908 逆序对

P1908 逆序对(树状数组解法)

luogu P1908 逆序对 |树状数组

洛谷 P1908 逆序对 Label:归并排序||树状数组

逆序对+离散树状数组+。。。。

树状数组求逆序对