算法训练 逆序对

ALGO-7 逆序对

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

Alice是一个让人非常愉跃的人!他总是去学习一些他不懂的问题,然后再想出许多稀奇古怪的题目。这几天,Alice又沉浸在逆序对的快乐当中,他已近学会了如何求逆序对对数,动态维护逆序对对数等等题目,他认为把这些题让你做简直是太没追求了,于是,经过一天的思考和完善,Alice终于拿出了一道他认为差不多的题目:
有一颗2n-1个节点的二叉树,它有恰好n个叶子节点,每个节点上写了一个整数。如果将这棵树的所有叶子节点上的数从左到右写下来,便得到一个序列a[1]…a[n]。现在想让这个序列中的逆序对数量最少,但唯一的操作就是选树上一个非叶子节点,将它的左右两颗子树交换。他可以做任意多次这个操作。求在最优方案下,该序列的逆序对数最少有多少。
Alice自己已近想出了题目的正解,他打算拿来和你分享,他要求你在最短的时间内完成。

输入格式

第一行一个整数n。
下面每行,一个数x。
如果x=0,表示这个节点非叶子节点,递归地向下读入其左孩子和右孩子的信息,如果x≠0,表示这个节点是叶子节点,权值为x。

输出格式

输出一个整数,表示最少有多少逆序对。

测试样例

输入:
3
0
0
3
1
2

输出:
1

数据规模与约定

对于20%的数据,n <= 5000。
对于100%的数据,1 <= n <= 200000,0 <= a[i]<2^31。

鏖战几天终于用JavaAC了

AC code:

import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.*;

public class Main {

    static Node[] tree;
    static int inReturn;
    static int[] noLeaf;
    static Queue<PQItem> inQ;

    public static void main(String[] args) throws IOException {
        InputReader in = new InputReader(System.in);
        int n = in.nextInt(); long cnt = 0;
        noLeaf = new int[n];
        tree = new Node[n*2];
        tree[0] = new Node(0);
        tree[1] = new Node(1);
        build(tree[1], 1, in);
        inQ = new PriorityQueue();
        for (int i = n - 2; i >= 0; i--) cnt += merge(noLeaf[i]);
        System.out.print(cnt);
    }


    static void build(Node node, int offset, InputReader in) throws IOException {
        LinkedList<Node> queue = new LinkedList();
        int index = 0;
        queue.addFirst(node);
        while (queue.size() > 0) {
            Node now = queue.poll();
            noLeaf[index] = now.weight;
            now.weight = in.nextInt();
            if (now.weight == 0) {
                now.left = ++offset;
                queue.addFirst(tree[++offset] = new Node(offset));
                now.right = offset;
                queue.addFirst(tree[offset - 1] = new Node(offset - 1));
                index++;
            } else now.size = 1;
        }
    }

    static long merge(int node) {
        long LS = tree[tree[node].left].size, RS = tree[tree[node].right].size, cnt = 0;
        if (LS > RS) {
            Queue(tree[node].right);
            tree[node] = tree[tree[node].left];
        } else {
            Queue(tree[node].left);
            tree[node] = tree[tree[node].right];
        }
        while (inQ.size() > 0) {
            inReturn = 0;
            insert(node, reSet(inQ.poll().node));
            cnt += inReturn;
        }
        return Math.min(cnt, LS * RS - cnt);
    }


    static void Queue(int node) {
        if (tree[node].left != 0) Queue(tree[node].left);
        if (tree[node].right != 0) Queue(tree[node].right);
        if (tree[node].weight != 0) inQ.offer(new PQItem(tree[node].weight, node));
    }

    static void insert(int node, int value) {
        ++tree[node].size;
        if (tree[node].weight >= tree[value].weight) {
            if (tree[node].left != 0) insert(tree[node].left, value);
            else  tree[node].left = value;
            maintain(node, true);
        } else {
            inReturn += tree[tree[node].left].size + 1;
            if (tree[node].right != 0) insert(tree[node].right, value);
            else tree[node].right = value;
            maintain(node, false);
        }
    }

    static int reSet(int node) {
        tree[node].size = 1;
        tree[node].left = 0;
        tree[node].right = 0;
        return node;
    }

    static void LeftRotate(int node) {
        Node temp = tree[node];
        int r = temp.right;
        tree[r].size = temp.size;
        temp.right = tree[r].left;
        temp.size = tree[temp.left].size + tree[temp.right].size + 1;
        tree[r].left = r;
        tree[node] = tree[r];
        tree[r] = temp;
    }

    static void RightRotate(int node) {
        Node temp = tree[node];
        int l = temp.left;
        tree[l].size = temp.size;
        temp.left = tree[l].right;
        temp.size = tree[temp.left].size + tree[temp.right].size + 1;
        tree[l].right = l;
        tree[node] = tree[l];
        tree[l] = temp;
    }

    static void maintain(int node, boolean flag) {
        if (flag) {
            if (tree[tree[tree[node].left].left].size > tree[tree[node].right].size) RightRotate(node);
            else if (tree[tree[tree[node].left].right].size > tree[tree[node].right].size) {
                LeftRotate(tree[node].left);
                RightRotate(node);
            } else return;
        } else {
            if (tree[tree[tree[node].right].right].size > tree[tree[node].left].size) LeftRotate(node);
            else if (tree[tree[tree[node].right].left].size > tree[tree[node].left].size) {
                RightRotate(tree[node].right);
                LeftRotate(node);
            } else return;
        }
        maintain(tree[node].left, true);
        maintain(tree[node].right, false);
    }

    static class Node {
        int weight;
        int size;
        int left;
        int right;

        Node(int weight) { this.weight = weight; }
    }

    static class PQItem implements Comparable<PQItem> {

        int index;
        int node;

        PQItem (int index, int node) {
            this.node = node;
            this.index = index;
        }

        @Override
        public int compareTo(PQItem o) {
            if (this.index > o.index) return -1;
            return +1;
        }
    }

    static class InputReader {

        BufferedReader read;
        StringTokenizer tokens;
        String delimiters;

        InputReader (InputStream in, String delimiters) {
            this.read = new BufferedReader(new InputStreamReader(in));
            this.delimiters = delimiters;
            this.tokens = new StringTokenizer("", delimiters);
        }

        InputReader (InputStream in) { this(in, " \t\n\r\f"); }

        String next() throws IOException {
            while (!tokens.hasMoreTokens()) tokens = new StringTokenizer(read.readLine(), delimiters);
            return tokens.nextToken();
        }

        int nextInt() throws IOException { return Integer.parseInt(next()); }

        void close() throws IOException { read.close(); }
    }
}

在这里插入图片描述

第一版(MLE)

import java.io.*;
import java.util.*;

public class Main {

    static List<Integer>[] Llist, Rlist;
    static int tree[], nodeIndex, listIndex;

    public static void main(String[] args) throws IOException {
        InputReader in = new InputReader(System.in);
        int n = in.nextInt() - 1, node = n * 2 + 1, cnt = 0;
        tree = new int[node];
        Llist = new List[n];
        Rlist = new List[n];
        for (int i = 0; i < node; i++) tree[i] = in.nextInt();
        if (tree[0] == 0) {
            Llist[0] = getList();
            Rlist[0] = getList();
        } else {
            nodeIndex = listIndex = -1;
            getList();
        }
        for (int l = 0, LWeight = 0, RWeight = 0; l < n; l++, LWeight = 0, RWeight = 0) {
            for (int i: Llist[l])
                for (int j: Rlist[l])
                    if (i > j) LWeight++;
                    else RWeight++;
            cnt += Math.min(LWeight, RWeight);
        }
        System.out.print(cnt);
    }

    static List getList() {
        if (tree[++nodeIndex] == 0) {
            final int index = ++listIndex;
            Llist[index] = getList();
            Rlist[index] = getList();
            return new ArrayList(Llist[index]) {{ addAll(Rlist[index]); }};
        }
        return new ArrayList() {{ add(tree[nodeIndex]); }};
    }

    static class InputReader {

        BufferedReader read;
        StringTokenizer tokens;
        String delimiters;

        InputReader (InputStream in, String delimiters) {
            this.read = new BufferedReader(new InputStreamReader(in));
            this.delimiters = delimiters;
            this.tokens = new StringTokenizer("", delimiters);
        }

        InputReader (InputStream in) { this(in, " \t\n\r\f"); }

        String next() throws IOException {
            while (!tokens.hasMoreTokens()) tokens = new StringTokenizer(read.readLine(), delimiters);
            return tokens.nextToken();
        }

        int nextInt() throws IOException { return Integer.parseInt(next()); }

        void close() throws IOException { read.close(); }
    }
}

在这里插入图片描述
遭受测试用例的毒打,如果是比赛的话我可能就信心满满的提交上去了

稍作优化调整(MLE)

import java.io.*;
import java.util.*;

public class Main {

    static Node[] noLeafPQ;
    static List<Integer>[] listPool;
    static int tree[], nodeIndex, PQIndex;

    public static void main(String[] args) throws IOException {
        InputReader in = new InputReader(System.in);
        int n = in.nextInt() - 1, node = n * 2 + 1, cnt = 0;
        tree = new int[node]; nodeIndex = PQIndex = -1;
        noLeafPQ = new Node[n];
        listPool = new List[n];
        for (int i = 0; i < node; i++) tree[i] = in.nextInt();
        put();
        for (int i = n - 1, poolIndex = 0; i >= 0; i--, poolIndex++) {
            List Llist = new ArrayList();
            List Rlist = new ArrayList();
            getList(noLeafPQ[i].left, Llist);
            getList(noLeafPQ[i].right, Rlist);
            noLeafPQ[i].weight = -262144 | poolIndex;
            cnt += getCount(Llist, Rlist);
            Llist.addAll(Rlist);
            listPool[poolIndex] = Llist;
        }
        System.out.print(cnt);
    }

    static int getCount(List<Integer> L, List<Integer> R) {
        int l = 0, r = 0;
        for (int i: L)
            for (int j: R)
                if (i > j) l++;
                else r++;
        return Math.min(l, r);
    }

    static void getList(Node N, List list) {
        if (N.weight == 0) {
            getList(N.left, list);
            getList(N.right, list);
        } else if (N.weight > 0) list.add(N.weight);
        else list.addAll(listPool[N.weight & 262143]);
    }

    static Node put() {
        if (tree[++nodeIndex] == 0) {
            Node n = new Node(0);
            n.left = put();
            n.right = put();
            return noLeafPQ[++PQIndex] = n;
        }
        return new Node(tree[nodeIndex]);
    }

    static class Node {

        int weight;
        Node left;
        Node right;

        Node (int weight) { this.weight = weight; }
    }

    static class InputReader { . . . }
}

在这里插入图片描述

很大程度上降低了递归深度,可以看到性能有空前的提升,但还是只有24分

自闭了,兄弟

我再研究会

用C++复写了一遍(MLE):

#include <iostream>
#include <vector>

using namespace std;

struct node {
    int weight, left, right;
} *tree;

void build(int &cur);
void getList(int cur, vector<int> &list);
long long clac(vector<int> &L, vector<int> &R);

vector<int> *listPool;
int n, root, *noLeaf;
long long cnt;

int main() {
    scanf("%d", &n); --n;
    listPool = new vector<int>[n];
    tree = new node[n * 2 + 1];
    noLeaf = new int[n];
    build(root);
    for (int i = n - 1, poolIndex = 0; i >= 0; --i, poolIndex++) {
        vector<int> Llist;
        vector<int> Rlist;
        getList(tree[noLeaf[i]].left, Llist);
        getList(tree[noLeaf[i]].right, Rlist);
        tree[noLeaf[i]].weight = -262144 | poolIndex;
        cnt += clac(Llist, Rlist);
        Llist.insert(Llist.end(), Rlist.begin(), Rlist.end());
        listPool[poolIndex] = Llist;
    }
    cout << cnt;
}

int treeIndex, noLeafIndex;
void build(int &cur) {
    cur = treeIndex++;
    scanf("%d", &tree[cur].weight);
    if (tree[cur].weight == 0) {
        noLeaf[noLeafIndex++] = cur;
        build(tree[cur].left);
        build(tree[cur].right);
    }
}

void getList(int cur, vector<int> &list) {
    if (tree[cur].weight == 0) {
        getList(tree[cur].left, list);
        getList(tree[cur].right, list);
    } else if (tree[cur].weight > 0) list.push_back(tree[cur].weight);
    else list.insert(list.end(), listPool[tree[cur].weight & 262143].begin(), listPool[tree[cur].weight & 262143].end());
}

long long clac(vector<int> &L, vector<int> &R) {
    long long l = 0, r = 0;
    for (int i = 0; i < L.size(); ++i)
        for (int j = 0; j < R.size(); ++j)
            if (L[i] > R[j]) l++;
            else r++;
    return l < r? l: r;
}

在这里插入图片描述
由此可见,是我想问题太片面了

经过一系列艰苦卓绝的优化,主要是考虑继不继续做这道题了,原理都得都懂,但测试平台的Java栈容不足以递归生存树,总之先写个半成品看看有没有跑满分的潜力。

半成品:

import java.io.*;
import java.util.*;

public class Main {

    static Node[] tree;
    static int[] noLeaf;

    public static void main(String[] args) throws IOException {
        InputReader in = new InputReader(System.in);
        int n = in.nextInt(); long cnt = 0;
        (tree = new Node[n * 2])[1] = new Node(0, 1);
        tree[0] = new Node(0, 0);
        noLeaf = new int[n];
        build(tree[1], 1, in);
        for (int i = n - 2; i >= 0; i--) cnt += merge(noLeaf[i]);
        System.out.print(cnt);
    }

    static void build(Node node, int offset, InputReader in) throws IOException {
        LinkedList<Node> queue = new LinkedList();
        int index = 0;
        queue.addFirst(node);
        while (queue.size() > 0) {
            Node now = queue.poll();
            noLeaf[index] = now.weight;
            now.weight = in.nextInt();
            if (now.weight == 0) {
                now.left = ++offset;
                queue.addFirst(tree[++offset] = new Node(noLeaf[index], offset));
                now.right = offset;
                queue.addFirst(tree[offset - 1] = new Node(noLeaf[index], offset - 1));
                index++;
            } else now.size = 1;
        }
    }

    static long merge(int node) {
        long LS = tree[tree[node].left].size, RS = tree[tree[node].right].size, cnt = 0;
        if (LS > RS) {
            Queue(tree[node].right);
            Overlay(node, tree[node].left);
        } else {
            Queue(tree[node].left);
            Overlay(node, tree[node].right);
        }
        while (inQ.size() > 0) {
            inReturn = 0;
            insert(node, reSet(inQ.poll().node));
            cnt += inReturn;
        }
        return Math.min(cnt, LS * RS - cnt);
    }

    static Queue<PQItem> inQ = new PriorityQueue();
    static void Queue(int node) {
        if (tree[node].left != 0) Queue(tree[node].left);
        if (tree[node].right != 0) Queue(tree[node].right);
        if (tree[node].weight != 0) inQ.offer(new PQItem(tree[node].weight, node));
    }

    static int inReturn;
    static void insert(int node, int value) {
        ++tree[node].size;
        if (tree[node].weight >= tree[value].weight) {
            if (tree[node].left != 0) insert(tree[node].left, value);
            else tree[node].left = value;
        } else {
            inReturn += tree[tree[node].left].size + 1;
            if (tree[node].right != 0) insert(tree[node].right, value);
            else tree[node].right = value;
        }
    }

    static void Overlay(int top, int node) { (tree[top] = tree[node]).top = tree[top].top; }

    static int reSet(int node) { . . .}

    static class Node {
        int weight;
        int top;
        int size;
        int left;
        int right;

        Node(int top, int weight) { this.top = top; this.weight = weight; }
    }

    static class PQItem implements Comparable<PQItem>{

        int index;
        int node;

        PQItem (int index, int node) {
            this.node = node;
            this.index = index;
        }

        @Override
        public int compareTo(PQItem o) {
            if (this.index > o.index) return -1;
            return +1;
        }
    }

    static class InputReader { . . . }
}

在这里插入图片描述
至少避免了的报错,接下来实现平衡二叉树就彻底起飞,大概

九成品:

import java.io.*;
import java.util.*;

public class Main {

    static Node[] tree;
    static int[] noLeaf;

    public static void main(String[] args) throws IOException {
        InputReader in = new InputReader(System.in);
        int n = in.nextInt(); long cnt = 0;
        noLeaf = new int[n];
        tree = new Node[n * 2];
        tree[0] = new Node(0);
        tree[1] = new Node(1);
        build(tree[1], 1, in);
        for (int i = n - 2; i >= 0; i--) cnt += merge(noLeaf[i]);
        System.out.print(cnt);
    }

    static void build(Node node, int offset, InputReader in) throws IOException {
        LinkedList<Node> queue = new LinkedList();
        int index = 0;
        queue.addFirst(node);
        while (queue.size() > 0) {
            Node now = queue.poll();
            noLeaf[index] = now.weight;
            now.weight = in.nextInt();
            if (now.weight == 0) {
                now.left = ++offset;
                queue.addFirst(tree[++offset] = new Node(offset));
                now.right = offset;
                queue.addFirst(tree[offset - 1] = new Node(offset - 1));
                index++;
            } else now.size = 1;
        }
    }

    static long merge(int node) {
        long LS = tree[tree[node].left].size, RS = tree[tree[node].right].size, cnt = 0;
        if (LS > RS) {
            Queue(tree[node].right);
            tree[node] = tree[tree[node].left];
        } else {
            Queue(tree[node].left);
            tree[node] = tree[tree[node].right];
        }
        while (inQ.size() > 0) {
            inReturn = 0;
            insert(node, reSet(inQ.poll().node));
            cnt += inReturn;
        }
        return Math.min(cnt, LS * RS - cnt);
    }

    static Queue<PQItem> inQ = new PriorityQueue();
    static void Queue(int node) {
        if (tree[node].left != 0) Queue(tree[node].left);
        if (tree[node].right != 0) Queue(tree[node].right);
        if (tree[node].weight != 0) inQ.offer(new PQItem(tree[node].weight, node));
    }

    static int inReturn;
    static void insert(int node, int value) {
        ++tree[node].size;
        if (tree[node].weight >= tree[value].weight) {
            if (tree[node].left != 0) insert(tree[node].left, value);
            else {
                tree[node].left = value;
                maintain(node, true);
            }
        } else {
            inReturn += tree[tree[node].left].size + 1;
            if (tree[node].right != 0) insert(tree[node].right, value);
            else {
                tree[node].right = value;
                maintain(node, false);
            }
        }
    }

    static int reSet(int node) { . . . }

    static void LeftRotate(int node) {
        Node temp = tree[node];
        int r = temp.right;
        tree[r].size = temp.size;
        temp.right = tree[r].left;
        temp.size = tree[temp.left].size + tree[temp.right].size + 1;
        tree[r].left = r;
        tree[node] = tree[r];
        tree[r] = temp;
    }

    static void RightRotate(int node) {
        Node temp = tree[node];
        int l = temp.left;
        tree[l].size = temp.size;
        temp.left = tree[l].right;
        temp.size = tree[temp.left].size + tree[temp.right].size + 1;
        tree[l].right = l;
        tree[node] = tree[l];
        tree[l] = temp;
    }

    static void maintain(int node, boolean flag) {
        if (flag) {
            if (tree[tree[tree[node].left].left].size > tree[tree[node].right].size) RightRotate(node);
            else if (tree[tree[tree[node].left].right].size > tree[tree[node].right].size) {
                LeftRotate(tree[node].left);
                RightRotate(node);
            } else return;
        } else {
            if (tree[tree[tree[node].right].right].size > tree[tree[node].left].size) LeftRotate(node);
            else if (tree[tree[tree[node].right].left].size > tree[tree[node].left].size) {
                RightRotate(tree[node].right);
                LeftRotate(node);
            } else return;
        }
        maintain(tree[node].left, true);
        maintain(tree[node].right, false);
        maintain(node, true);
        maintain(node, false);
    }

    static class Node { . . . }

    static class PQItem implements Comparable<PQItem> { . . . }

    static class InputReader { . . . }
}

在这里插入图片描述
但是性能并没有提升,不过在自己电脑跑测试数据的时候出现了栈溢出错误,如果完整的实现了平衡二叉树,那么 100000 个节点的深度肯定不足以让我爆栈,有时间再写

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值