[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);
}

 

posted @ 2018-08-28 17:43  天之道,利而不害  阅读(118)  评论(0编辑  收藏  举报