[洛谷P3521][POI2011]ROT-Tree Rotations
阿新 • • 發佈:2018-11-02
題目大意:給一棵$n(n\leqslant2\times10^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\n", ans); return 0; }