2 条题解

  • 0
    @ 2025-4-16 0:00:25

    使用归并排序:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    // 使用归并排序方法统计逆序对数量
    long long mergeAndCount(vector<long long>& nums, int left, int mid, int right) {
        vector<long long> temp(right - left + 1);
        int i = left, j = mid + 1, k = 0;
        long long inv_count = 0;
        
        while (i <= mid && j <= right) {
            if (nums[i] <= nums[j]) {
                temp[k++] = nums[i++];
            } else {
                temp[k++] = nums[j++];
                inv_count += (mid - i + 1); // 关键统计步骤
            }
        }
        
        // 复制剩余元素
        while (i <= mid) temp[k++] = nums[i++];
        while (j <= right) temp[k++] = nums[j++];
        
        // 将排序后的数组复制回原数组
        for (i = left, k = 0; i <= right; i++, k++) {
            nums[i] = temp[k];
        }
        
        return inv_count;
    }
    
    long long mergeSortAndCount(vector<long long>& nums, int left, int right) {
        if (left >= right) return 0;
        
        int mid = left + (right - left) / 2;
        long long inv_count = 0;
        
        inv_count += mergeSortAndCount(nums, left, mid);
        inv_count += mergeSortAndCount(nums, mid + 1, right);
        inv_count += mergeAndCount(nums, left, mid, right);
        
        return inv_count;
    }
    
    long long countInversions(vector<long long>& a) {
        // 创建临时副本以避免修改原数组
        vector<long long> temp = a;
        return mergeSortAndCount(temp, 0, temp.size() - 1);
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        
        int n, m;
        cin >> n >> m;
        vector<long long> a(n);
        for(int i = 0; i < n; i++){
            cin >> a[i];
        }
        
        for(int op = 0; op < m; op++){
            int type;
            cin >> type;
            if(type == 1) {
                // 单点修改:1 x d
                int x;
                long long d;
                cin >> x >> d;
                a[x - 1] += d;
            } else if(type == 2) {
                // 区间修改:2 l r d
                int l, r;
                long long d;
                cin >> l >> r >> d;
                for(int i = l - 1; i < r; i++){
                    a[i] += d;
                }
            } else if(type == 3) {
                // 逆序对查询
                cout << countInversions(a) << "\n";
            }
        }
        return 0;
    }
    
    • 0
      @ 2025-4-15 23:59:42

      树状数组方法

      #include <iostream>
      #include <vector>
      #include <algorithm>
      using namespace std;
      
      // 树状数组(Fenwick Tree)结构,用于统计频次
      struct BIT {
          int n;
          vector<long long> tree;
          BIT(int n): n(n), tree(n+1, 0) {}
          
          // 单点更新:将下标 i 的值增加 delta
          void update(int i, long long delta) {
              for(; i <= n; i += i & -i)
                  tree[i] += delta;
          }
          
          // 前缀查询:求下标 1 到 i 的累计值
          long long query(int i) {
              long long s = 0;
              for(; i > 0; i -= i & -i)
                  s += tree[i];
              return s;
          }
      };
      
      // 利用树状数组计算当前数组 a 的逆序对总数,时间复杂度 O(n log n)
      // 这里先对 a 的值进行坐标压缩,确保 BIT 数组规模不超过元素种数
      long long countInversionsBIT(const vector<long long>& a) {
          int n = a.size();
          vector<long long> sorted = a;
          sort(sorted.begin(), sorted.end());
          sorted.erase(unique(sorted.begin(), sorted.end()), sorted.end());
          int m = sorted.size();
          
          BIT bit(m);
          long long inv = 0;
          // 从右往左扫描,统计每个 a[i] 之前有多少元素小于它
          for (int i = n - 1; i >= 0; i--) {
              int pos = lower_bound(sorted.begin(), sorted.end(), a[i]) - sorted.begin() + 1;
              inv += bit.query(pos - 1);
              bit.update(pos, 1);
          }
          return inv;
      }
      
      int main(){
          ios::sync_with_stdio(false);
          cin.tie(nullptr);
          
          int n, m;
          cin >> n >> m;
          vector<long long> a(n);
          for (int i = 0; i < n; i++){
              cin >> a[i];
          }
          
          // 处理 m 次操作
          // 操作类型:
          // 1 x d   -> 单点修改:将 a[x-1] 增加 d
          // 2 l r d -> 区间修改:将区间 [l-1, r-1] 的每个元素增加 d
          // 3       -> 逆序对查询:输出当前数组 a 的逆序对总数
          for (int op = 0; op < m; op++){
              int type;
              cin >> type;
              if (type == 1) {
                  int x;
                  long long d;
                  cin >> x >> d;
                  a[x - 1] += d;
              } else if (type == 2) {
                  int l, r;
                  long long d;
                  cin >> l >> r >> d;
                  for (int i = l - 1; i < r; i++){
                      a[i] += d;
                  }
              } else if (type == 3) {
                  // 每次查询时,利用 BIT 动态统计当前逆序对总数
                  cout << countInversionsBIT(a) << "\n";
              }
          }
          return 0;
      }
      
      
      • 1

      信息

      ID
      1137
      时间
      1000ms
      内存
      256MiB
      难度
      10
      标签
      递交数
      9
      已通过
      0
      上传者