【Luogu】P5094 [USACO04OPEN] MooFest G 加强版
P5094 [USACO04OPEN] MooFest G 加强版 - 洛谷
思路:
对于这种求 max 的操作好像很麻烦,但是如果我们排序后就好求了
对于第 i 个位置,前 i - 1 个位置肯定都小于当前位置,所以我们直接就知道本位置的 v[i] 了
那么对于绝对值呢?我们可以拆成两部分,一部分是大于,一部分是小于
实际求的过程中我们只需要计算一部分即可,因为另一部分可以利用前缀和求出来
具体的,我们求 i 前所有小于 x[i] 的数的 总和 big 和数量 cnt
那么小于 x[i] 的奉献就是 x[i] * cnt - big,对于大的则是 sum - big - x[i] * (i - cnt)
对于求 big 和 cnt 我们可以使用树状数组快速求出
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define yes cout << "YES\n"
#define no cout << "NO\n"
mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
//小于等于 i 的数量
int tree[50005];
//小于等于 i 的和
int tree2[50005];int lowbit(int x)
{return x & -x;
}void update(int x,int val)
{for(;x <= 50000;x += lowbit(x)){tree[x]++;tree2[x] += val;}
}pair<int,int> query(int x)
{int sum = 0,cnt = 0;for(;x;x -= lowbit(x)){cnt += tree[x];sum += tree2[x];}return {cnt,sum};
}void solve()
{int n;cin >> n;vector<pair<int,int>> a(n);int ans = 0;for (int i = 0; i < n; i++){cin >> a[i].first >> a[i].second;}sort(a.begin(),a.end());int sum = 0;for (int i = 0; i < n; i++){auto [cnt,big] = query(a[i].second);int add = (a[i].second * cnt) - big;add += (sum - big) - (a[i].second * (i-cnt));ans += add * a[i].first;sum += a[i].second;update(a[i].second,a[i].second);}cout << ans << endl;
}signed main()
{cin.tie(0)->sync_with_stdio(0);int t = 1;while (t--){solve();}return 0;
}