树状数组求逆序对

树状数组求逆序对

树状数组可以进行Point Update Interval Query 点更新,段求和的操作。同时也可以进行求逆序对。
首先要先了解树状数组的概念,树状数组是一种数据结构,具体的讲解我不写了,这个不是今天的重点 具体讲解

  • 步入正题
    在使用树状数组求逆序对中,树状数组的背景含义将有所变化。 以a[]数组表示我们要存储的一个数列,tree[]表示树状数组。初始化我们把tree数组全部置为 0 。表示序列a中的数我们目前一个都还没有插入到树状数组中。当我们执行add(a[i],1); 表示我把a[i],这个数据插入到了树状数组中去了。add参数是1表示插入。这样的好处是我们在统计小于a[i]的数有多少个时,直接使用query(a[i])就可以知道了。为什么这样呢?因为有一个比a[i]小我们加1,不相当于在树状数组中插入1吗。然后我们执行 sum+=i-query(a[i]); sum代表逆序对的个数计数。根据逆序对的定义我们不难理解为什么a[i]的逆序对是 i-query(a[i])。
    因为只有a[i]>a[j] && i
  • 我这里贴的是hdu1394 这道题中还有个结论

这里我们谈到的a[i]都是1–n之间的连续的n个数,当数列中的数不再是连续的1–n之间的数时,我们就要采用离散化的手段,记录数在数列中的位置

/*
 * Author:  looooop
 * Created Time:  2019/3/15 17:28:38
 * File Name: MinimumInversionNumber.cpp
 */

#include "bits/stdc++.h"

using namespace std;
#define lson 2*i
#define rson 2*i+1
#define LS l,mid,lson
#define RS mid+1,r,rson
#define UP(i,x,y) for(i=x;i<=y;i++)
#define DOWN(i,x,y) for(i=x;i>=y;i--)
#define MEM(a,x) memset(a,x,sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define LL long long
#define N 1000005
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define EXP 1e-8
#define lowbit(x) (x&-x)
#define MAX  6000
int a[MAX];
int n;
int tree[MAX];
void add(int x,int value) {
    for (int i = x; i <= n; i+=lowbit(i)) {
        tree[i] += value;
    }
}
void init() {
    MEM(tree,0);
}
int query(int x) {
    int res = 0;
    for (int i = x; i>0; i-=lowbit(i)) {
        res += tree[i];
    }
    return res;
}
int main(int argc,char *argv[]) {
    while(~scanf("%d", &n)) {
        init();
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            a[i];
            add(a[i]+1,1);
            cnt += i-query(a[i]+1);
        }
        int ans = cnt;
        for (int i = 1; i <= n; i++) {
            cnt += (n-a[i]-1)-a[i];
            if (cnt < ans)	ans = cnt;
        }	
        printf("%d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(模板)