[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; }
| 欢迎来原网站坐坐! >原文链接<