• 逆序对


    逆序对

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

    归并排序

    归并排序的思想就是递归分治,把要解决的区间分成两个区间比较(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 <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #define lowbit(n) (n & (-n))
    #define int long long
    using 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 <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ls left, mid, root << 1
    #define rs mid + 1, right, root << 1 | 1
    #define int long long
    using 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; 
    }	
    
  • 相关阅读:
    代码高亮测试
    docker详解
    生成python项目的docker模板
    Windows下载Ubuntu的文件,用WinSCP软件(建议用MobeXterm),Ubuntu开启SSH连接
    分配堆内存的四种方式
    像素和rgb
    自由飞翔
    像素和分辨率的关系
    DOM事件阶段以及事件捕获与事件冒泡先后执行顺序
    有点甜 汪苏泷
  • 原文地址:https://www.cnblogs.com/liuwenyao/p/10705079.html
Copyright © 2020-2023  润新知