[bzoj4240]有趣的家庭菜园_树状数组
有趣的家庭菜园
题目链接:https://lydsy.com/JudgeOnline/problem.php?id=4240
数据范围:略。
题解:
第一步比较简单,只需要排序之后,每个数不是在左边就是在右边。
我们只需要计算出,当前这个数如果在左边,能跟没放进数列的数构成的逆序对数和在右边哪个更小。
这个过程可以用树状数组维护。
代码:
#include <bits/stdc++.h>
#define N 1000010
using namespace std;
typedef long long ll;
char *p1, *p2, buf[100000];
#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
int rd() {
int x = 0, f = 1;
char c = nc();
while (c < 48) {
if (c == '-')
f = -1;
c = nc();
}
while (c > 47) {
x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
}
return x * f;
}
int tr[N];
inline int lowbit(int x) {
return x & (-x);
}
void upd(int x, int val) {
for (int i = x; i < N; i += lowbit(i)) {
tr[i] += val;
}
}
int qry(int x) {
int ans = 0;
for (int i = x; i; i -= lowbit(i)) {
ans += tr[i];
}
return ans;
}
struct Node {
int val, id;
}a[N];
inline bool cmp(const Node &a, const Node &b) {
return a.val > b.val;
}
int main() {
int n = rd();
for (int i = 1; i <= n; i ++ ) {
a[i].val = rd(), a[i].id = i;
}
ll ans = 0;
sort(a + 1, a + n + 1, cmp);
for (int i = 1; i <= n; ){
int j;
for (j = i; j <= n; j ++ ) {
int mdl = qry(a[j].id);
ans += min(mdl, i - 1 - mdl);
if (a[j + 1].val != a[j].val) {
break;
}
}
for (; i <= j; i ++ ) {
upd(a[i].id, 1);
}
}
cout << ans << endl ;
return 0;
}
| 欢迎来原网站坐坐! >原文链接<

浙公网安备 33010602011771号