博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
逆序对
阅读量:5155 次
发布时间:2019-06-13

本文共 3623 字,大约阅读时间需要 12 分钟。

逆序对

逆序对非常常见,有三种求解的方法,效率差不多,但是树状数组法较快。

归并排序

归并排序的思想就是递归分治,把要解决的区间分成两个区间比较\(a_i\)\(a_j\)的大小(其中\(a_i\)属于左区间,\(a_j\)属于右区间,其实就是将左右区间合并、并排序),若\(a_i<a_j\),则将\(a_i\)复制到\(r_k\)中,然后将\(i\)\(k\)都加\(11\),否则将\(a_j\)复制到\(r_k\)中,将\(j,k\)\(11\),最后再将\(r_k\)移动到\(a_i\)中,然后继续合并;

void msort(int l, int r){    if(l == r)    return;    int mid = (l + r) / 2;    msort(l, mid);    msort(mid + 1, r);    int i = l;    int j = mid + 1;    int k = l;    while (i <= mid && j <= r)    {        if (a[i] <= a[j])        {            fu[k] = a[i];            k++; i++;        }        else        {            fu[k] = a[j];            k++;            j++;            ans += mid - i + 1;        }    }    while (i <= mid)    {        fu[k] = a[i];        k++;        i++;    }    while (j <= r)    {        fu[k] = a[j];        k++;        j++;    }    for (int i = l; i <= r; i++)    a[i] = fu[i];}

树状数组

树状数组其实就是桶的思想进行一波优化所得出来的。每拿到一个值放入桶中,统计所有大于这个数的数量,然后累加,发现这正好可以用树状数组优化。当然在使用之前还是应该离散化一下,不然桶会炸的。

#include 
#include
#include
#include
#define lowbit(n) (n & (-n))#define int long longusing namespace std;int n, sum;int a[1001000], b[1010000], tree[1000100];void add(int x) { while (x <= n) { tree[x]++; x += lowbit(x); }}int query(int x) { int ans = 0; while (x > 0) { ans += tree[x]; x -= lowbit(x); } return ans;}bool cmp(const int &x, const int &y){ if(b[x]==b[y]) return x > y; return b[x] > b[y];}signed main() { scanf("%lld", &n); for(register int i = 1; i <= n; i++) { scanf("%lld", &b[i]); a[i] = i; } sort(a + 1, a + n + 1, cmp); for (int i = 1; i <= n; i++) { add(a[i]); sum += query(a[i] - 1); } printf("%lld", sum);}

线段树

一般的线段树并不能解决这个问题,而且需要用权值线段树来解决这种问题。

#include 
#include
#include
#include
#define ls left, mid, root << 1#define rs mid + 1, right, root << 1 | 1#define int long longusing namespace std;int data[1010000], ans = 0;struct ha { int num, id;}a[1001000];struct t { int l, r, sum;}tree[2001000];bool cmp(ha a, ha b){ return a.num < b.num;}inline void build(int left, int right, int root){ tree[root].l = left; tree[root].r = right; if (left == right) return; int mid = (left + right) >> 1; build(ls), build(rs);}inline void pushup(int root){ tree[root].sum = tree[root << 1].sum + tree[root << 1 | 1].sum; }void update(int root, int add){ if (tree[root].l == tree[root].r) { tree[root].sum ++; return; } int mid = (tree[root].l + tree[root].r) >> 1; if (add <= mid) update(root << 1, add); else update(root << 1 | 1, add); pushup(root); return;} int query(int root, int a){ if (tree[root].l == tree[root].r) return tree[root].sum; int mid = (tree[root].l + tree[root].r) >> 1; if (a <= mid) return tree[root << 1 | 1].sum + query(root << 1, a); else return query(root << 1 | 1, a);}signed main(){ int n; scanf("%lld", &n); for (int i = 1; i <= n; i++) scanf("%lld", &data[i]), a[i].id = i, a[i].num = data[i]; sort(a + 1, a + 1 + n, cmp);// for (int i = 1, j = 0; i <= n; i++) { if (a[i].num != a[i - 1].num || i == 1) j++; data[a[i].id] = j; } //此处向上为离散化。 build(1, n, 1); for (int i = 1; i <= n; i++) { ans += query(1, data[i] + 1);//要算比data[i]严格大于的数。 update(1, data[i]); } printf("%lld", ans); return 0; }

转载于:https://www.cnblogs.com/liuwenyao/p/10705079.html

你可能感兴趣的文章
[No0000F9]C# 运算符重载
查看>>
如何设置IntelliJ IDEA智能感知支持Jsp内置对象
查看>>
CUBRID学习笔记 46 PREPARED set Do
查看>>
C++模板学习:函数模板、结构体模板、类模板
查看>>
2015/8/29 Python基础(3):数值
查看>>
Ora-19804: Cannot reclaim 45561856 bytes disk space from 8589934592 limit
查看>>
自己定义控件-仿iphone之ToggleButton&amp;VoiceSeekBar
查看>>
正则表达式
查看>>
Android点击效果
查看>>
JAVA问题集锦Ⅰ
查看>>
写在前面的话
查看>>
java匿名对象_面向对象
查看>>
【坑】——待填?!
查看>>
LeetCode: Single Number I & II
查看>>
构建最小JDK Docker镜像 或者直接使用镜像:frolvlad/alpine-oraclejre8:slim
查看>>
hah
查看>>
js detect the type of device
查看>>
查看daemon使用技巧
查看>>
jzxx1000~1010题分析
查看>>
Windows Phone 8 与 windows 8 开发技术概览
查看>>