[POI2011]ROT-Tree Rotations
题目:传送门
题解:对每个叶子建立一颗线段树,从底向上合并两个儿子。以节点 u 为根的子树的逆序对 = 以 lson[ u ] 为根的子树的逆序对 + 以 rson[ u ] 为根的子树的逆序对 + 跨过 lson[ u ] 和 rson[ u ] 的逆序对。
const int N = 200005; LL ansl, ansr, ans; int n, cnt, tot; int v[2 * N], l[2 * N], r[2 * N], ls[20 * N], rs[20 * N], root[20 * N], sum[20 * N]; void readTree(int x) { sc(v[x]); if (!v[x]) { l[x] = ++cnt; readTree(l[x]); r[x] = ++cnt; readTree(r[x]); } } void Pushup(int rt) { sum[rt] = sum[ls[rt]] + sum[rs[rt]]; } void Build(int l, int r, int &rt, int pos) { if (!rt) rt = ++tot; if (l == r) { sum[rt] = 1; return; } int mid = (l + r) >> 1; if (pos <= mid) Build(l, mid, ls[rt], pos); else Build(mid + 1, r, rs[rt], pos); Pushup(rt); } int Merge(int x, int y) { if (!x || !y) return x ^ y; ansl += 1ll * sum[ls[x]] * sum[rs[y]]; ansr += 1ll * sum[rs[x]] * sum[ls[y]]; ls[x] = Merge(ls[x], ls[y]); rs[x] = Merge(rs[x], rs[y]); Pushup(x); return x; } void DFS(int x = 1) { if (!x) return; DFS(l[x]); DFS(r[x]); if (!v[x]) { ansl = ansr = 0; root[x] = Merge(root[l[x]], root[r[x]]); ans += min(ansl, ansr); } } int main() { sc(n); cnt++; readTree(1); Rep(i, 1, cnt) if (v[i]) Build(1, n, root[i], v[i]); DFS(1); printf("%lld\n", ans); }