Solution

cookiebus 2023-03-18 8:40:17 16 返回题目

本题有两种做法,做法一,基于树状数组优化,做法二,分治法

这里讲一下分治做法(类似归并排序):

作为第一关键字排序, for j=mid+1 to r 枚举的贡献和

由归并排序特点,两个区间内已经按照第二关键字排好序。寻找和x>x_jx<x_jx_i$。贡献和为

moo.png

前缀和预处理,查询复杂度$O(1)。

贡献加完后,对第二关键字归并排序。

参考代码如下:

#include <bits/stdc++.h>
using namespace std;
#define int long long

struct node {
    int x, v;
} a[50005];
bool cmp(node aa, node bb) {
    return aa.v < bb.v;  //按v从小到大排序
}
int ans = 0, sum[50005];
void merge(int l, int r) {
    int mid = (l + r) / 2;
    sum[l - 1] = 0;
    for (int i = l; i <= r; i++) {
        sum[i] = sum[i - 1] + a[i].x;
    }
    for (int j = mid + 1; j <= r; j++) {
        int ii = l - 1;  // i:寻找x<xj的所有x,i标志分界线(最后一个满足的):由于归并排序,已经按x从小到大排序
        while (ii < mid && a[ii + 1].x < a[j].x) {
            ii++;
        }
        ans += a[j].v *
               ((ii - l + 1) * a[j].x - (sum[ii] - sum[l - 1]) + (sum[mid] - sum[ii]) - (mid - ii) * a[j].x);
    }
    //中间跨越部分处理完成后,即可对合并的整体按第二关键字x排序,不影响后续结果。
    node aux[r - l + 1];
    for (int i = l; i <= r; i++) {
        aux[i - l] = a[i];
    }
    int i1 = l, i2 = mid + 1;
    for (int i = l; i <= r; i++) {
        if (i1 > mid) {
            a[i] = aux[i2 - l];
            i2++;
        } else if (i2 > r) {
            a[i] = aux[i1 - l];
            i1++;
        } else if (aux[i1 - l].x >= aux[i2 - l].x) {
            a[i] = aux[i2 - l];
            i2++;
        } else {
            a[i] = aux[i1 - l];
            i1++;
        }
    }
}
void mergesort(int l, int r) {
    if (l >= r)
        return;
    int mid = (l + r) / 2;
    mergesort(l, mid);
    mergesort(mid + 1, r);
    merge(l, r);
}
signed main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i].v >> a[i].x;
    }
    sort(a, a + n, cmp);
    mergesort(0, n - 1);
    cout << ans;
}
{{ vote && vote.total.up }}