学习笔记:逆序对
tsqtsqtsq0309 · · 算法·理论
逆序对
引入
对于给定的一段正整数序列,逆序对就是序列中
—— 洛谷 P1908 逆序对
实现
首先贴出一道例题。
洛谷 P1908 逆序对
关于逆序对的定义:对于给定的一段正整数序列,逆序对就是序列中
一眼逆序对。
我们可以考虑直接枚举,显然答案有:
总的时间复杂度
#include <iostream>
#define int long long
#define MAXN 500005
using namespace std;
int n, a[MAXN], ans;
int read(){
int t = 1, x = 0;char ch = getchar();
while(!isdigit(ch)){if(ch == '-')t = -1;ch = getchar();}
while(isdigit(ch)){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * t;
}
signed main(){
n = read();
for(int i = 1 ; i <= n ; i ++)a[i] = read();
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j < i ; j ++)
if(a[i] < a[j])ans++;
cout << ans << endl;return 0;
}
然而:
看来暴力显然是不够的……
需要一些乱搞。
需要一些高级优化。
考虑树状数组。首先对于逆序对,我们可以如此思考这个问题:对于每个数的逆序对,在一个数列中的数量都是一定的。那么我们可以对于数列
首先离散化一下,再按价值从大到小排序。排完序之后用树状数组维护,每次把这个数的位置加入到树状数组中(因为是排完序之后,所以之前加入的一定比后加入的大),然后在查询当前这个数前面位置的数(是前面位置的数,要当前这个数
#include <iostream>
#include <algorithm>
#define int long long
#define MAXN 500005
using namespace std;
int n, tree[MAXN], ans;
struct node{
int a, b;
bool friend operator<(node a, node b){
if(a.a == b.a)return a.b > b.b;
else return a.a > b.a;
}
}a[MAXN];
int read(){
int t = 1, x = 0;char ch = getchar();
while(!isdigit(ch)){if(ch == '-')t = -1;ch = getchar();}
while(isdigit(ch)){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * t;
}
void write(int x){
if(x < 0){putchar('-');x = -x;}
if(x >= 10)write(x / 10);
putchar(x % 10 ^ 48);
}
int lowbit(int x){return x & -x;}
void update(int x, int k){
for(int i = x ; i <= n ; i += lowbit(i))
tree[i] += k;
}
int query(int x){
int res = 0;
for(int i = x ; i >= 1 ; i -= lowbit(i))
res += tree[i];
return res;
}
signed main(){
n = read();
for(int i = 1 ; i <= n ; i ++)a[i].a = read();
for(int i = 1 ; i <= n ; i ++)a[i].b = i;
sort(a + 1, a + n + 1);
for(int i = 1 ; i <= n ; i ++)
update(a[i].b, 1),ans += query(a[i].b - 1);
write(ans);putchar('\n');return 0;
}
然后就切了……