• 数状数组 及其在 求逆序对中的应用


    讲解链接


    如果树状数组维护的是a数组的值,那么 sum[i] 表示在 a 数列1~i中的元素的和
    查询(l,r)中元素的和就为 sum(r)-sum(l)


    逆序对的定义: i < j && a[i] > a[j]
    例题中的逆序对: pre[i]为1~i中a[i]的个数; nex[i]为i~n中a[i]的个数
    这时候的逆序对就是,i < j && pre[i] > nex[j]
    注意求法,很神奇


    题目链接:

    #include<iostream>
    #include <cstdio>
    #include <map>
    using namespace std;
    typedef long long ll;
    const int maxn = 1000017;
    int n;
    int a[maxn], c[maxn];
    int nex[maxn], pre[maxn];
    ll res;
    map <int, int> freq;
    int Lowbit(int x) //2^k
    {
        return x&(-x);
    }
    
    void update(int i, int x)//i点增量为x
    {
        while (i <= n)
        {
            c[i] += x;
            i += Lowbit(i);
        }
    }
    int sum(int x)//区间求和 [1,x]
    {
        int sum = 0;
        while (x > 0)
        {
            sum += c[x];
            x -= Lowbit(x);
        }
        return sum;
    }
    
    int main() {
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        //pre[i]为1~i中a[i]的个数
        //nex[i]为i~n中a[i]的个数
        for (int i = 0; i < n; i++) {
            pre[i] = ++freq[a[i]];
        }
        freq.clear();
        for (int i = n - 1; i > 0; i--) {
            nex[i] = ++freq[a[i]];
        }
        for (int i = 0; i < n; i++) {
            //这两步可以说是很精妙了,首先当插入i之后,我们query的时候i的坐标已经+1了
            //这时候我们查询序列中有多少个数比nex[i]大其实就是查询数组中有多少个数比nex[i]大
            //一个数组的话就是update谁,就查询谁
            res += i - sum(nex[i]);
            update(pre[i], 1);
        }
        cout << res << endl;
        return 0;
    }
  • 相关阅读:
    Analyzing the Go runtime scheduler from source code perspective
    golang教材
    Kafka#4:存储设计 分布式设计 源码分析
    机器学习应该准备哪些数学预备知识?
    Why does deep learning work?
    Deep Reinforcement Learning
    How do I learn machine learning?
    What are some good books/papers for learning deep learning?
    why deep learning works
    AI 名校课程&书籍 需要学习
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/9489807.html
Copyright © 2020-2023  润新知