经典题。tag:数状数组
。
开一个权值树状数组,从左往右遍历,统计左边比 \(y_i\) 小的数字个数 \(ul_i\) 与比 \(a_i\) 大的数字个数 \(dl_i\);然后从右往左遍历,统计右边比 \(y_i\) 小的数字个数 \(dr_i\) 与比 \(a_i\) 大的数字个数 \(ur_i\)。
两个答案即为 \(\sum_{i=1}^n dl_i \cdot ur_i\),\(\sum_{i=1}^n ul_i \cdot dr_i\)。
当然用线段树也可以。树状数组优势在于代码很好写。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5+10;
int n; ll c[N], a[N], ul[N], dl[N], ur[N], dr[N];
int lbt(int x) {return x & -x;}
void add(int k, ll x) {for (int i = k; i <= n; i += lbt(i)) c[i] += x;}
ll qry(int k) {ll rs = 0; for (int i = k; i; i -= lbt(i)) rs += c[i]; return rs;}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++) {
if(i > 1) dl[i] = qry(n) - qry(a[i]), ul[i] = qry(a[i] - 1);
add(a[i], 1);
}
memset(c, 0, sizeof c);
for (int i = n; i; i--) {
if(i < n) ur[i] = qry(n) - qry(a[i]), dr[i] = qry(a[i] - 1);
add(a[i], 1);
}
ll ans1 = 0, ans2 = 0;
for (int i = 1; i <= n; i++) ans1 += dl[i] * ur[i], ans2 += ul[i] * dr[i];
printf("%lld %lld", ans1, ans2);
return 0;
}
标签:dl,int,题解,ll,P10589,ur,qry,dr
From: https://www.cnblogs.com/Running-a-way/p/18283193