题目大意:给一棵$n(nleqslant2 imes10^5)$个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少。输出最少的逆序对个数
题解:线段树合并,对于每个节点求出交换左右子树和不交换的答案。
卡点:没开$long;long$
C++ Code:
#include <cstdio> #define maxn 200010 #define N maxn * 20 inline long long min(long long a, long long b) {return a < b ? a : b;} int n, root; long long ans, res0, res1; int lc[N], rc[N], sum[N], idx; int merge(int x, int y) { if (!x || !y) return x | y; res0 += static_cast<long long> (sum[lc[x]]) * sum[rc[y]]; res1 += static_cast<long long> (sum[rc[x]]) * sum[lc[y]]; sum[x] = sum[x] + sum[y]; lc[x] = merge(lc[x], lc[y]); rc[x] = merge(rc[x], rc[y]); return x; } int insert(int l, int r, int val) { int rt = ++idx; sum[rt] = 1; if (l == r) return rt; int mid = l + r >> 1; if (val <= mid) lc[rt] = insert(l, mid, val); else rc[rt] = insert(mid + 1, r, val); return rt; } int init() { int x; scanf("%d", &x); if (x) return insert(1, n, x); else { int l = init(), r = init(), root; res0 = res1 = 0; root = merge(l, r); ans += min(res0, res1); return root; } } int main() { scanf("%d", &n); root = init(); printf("%lld ", ans); return 0; }