Separating Numbers

We are given a tree with N nodes. Each node has a color Ci. We are also given N1 queries and in each query we are told to destroy a previously undestroyed edge. Every time we destroy an edge, we have to report the number of pairs of nodes that get disconnected. Here, two nodes i and j are said to be disconnected  if before the destruction you could reach from i to j using edges not yet destroyed , and if Ci=Cj.

Constraint:

N300,000

C[i]100,000

Example:

Input:
5 5 4 2 5 3 2 1 2 5 1 5 4 5 2 1 3 4
Output:
2 0 1 0

Approach

Java

import java.util.Map;
import java.util.TreeMap;

public class SeparatingNumbers {
    private static int C = 312345;
    private static long[] ans = new long[C];

    public static void main(String[] args) {
        int N = 5;

        int ar2D[][] = { { 54 }, { 25 }, { 32 }, { 12 } };
        int[] u = new int[C];
        int[] v = new int[C];
        for (int i = 0; i < N - 1; i++) {
            u[i] = ar2D[i][0] - 1;
            v[i] = ar2D[i][1] - 1;
        }
        int[] c = { 51545 };
        // in order -1
        int[] order = { 1023 };
        DisjointSetUnion dsu = new DisjointSetUnion(N, c);
        for (int i = N - 2; i >= 0; i--) {
            int x = u[order[i]];
            int y = v[order[i]];
            ans[i] = dsu.merge(x, y);
        }
        for (int i = 0; i < N - 1; i++) {
            System.out.println(ans[i]);
        }
    }

    static public class DisjointSetUnion {

        private int rank[], parent[], size[];
        private TreeMap<IntegerIntegermap[];
        private int n;

        public DisjointSetUnion(int nint c[]) {
            this.n = n;
            makeSet(c);
        }

        private void makeSet(int c[]) {
            rank = new int[n];
            parent = new int[n];
            map = new TreeMap[n];
            size = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                size[i] = 1;
                map[i] = new TreeMap<>();
                increment(map[i], c[i], 1);
            }
        }

        public int find(int x) {
            if (parent[x] != x)
                parent[x] = find(parent[x]);
            return parent[x];
        }

        public long merge(int xint y) {
            int xRoot = find(x);
            int yRoot = find(y);

            if (xRoot == yRoot)
                return getCount(map[xRoot], map[xRoot]);

            size[xRoot] = size[yRoot] = size[xRoot] + size[yRoot];

            long count = getCount(map[xRoot], map[yRoot]);

            if (rank[xRoot] < rank[yRoot]) {
                parent[xRoot] = yRoot;
                merge(map[yRoot], map[xRoot]);
            } else {
                parent[yRoot] = xRoot;
                merge(map[xRoot], map[yRoot]);
                if (rank[xRoot] == rank[yRoot]) {
                    rank[xRoot]++;
                }
            }

            return count;
        }

        // into x
        private void merge(TreeMap<IntegerIntegerxTreeMap<IntegerIntegery) {
            for (Map.Entry<IntegerIntegerentry : y.entrySet()) {
                increment(x, entry.getKey(), entry.getValue());
            }
        }

        private long getCount(TreeMap<IntegerIntegerxTreeMap<IntegerIntegery) {
            if (x.size() > y.size()) {
                return getCount(y, x);
            }
            long ans = 0;
            for (Map.Entry<IntegerIntegerentry : x.entrySet()) {
                ans += (longentry.getValue() * get(y, entry.getKey());
            }
            return ans;
        }
    }

    static void increment(TreeMap<IntegerIntegermapint keyint x) {
        Integer value = map.get(key);
        if (value == null) {
            map.put(key, x);
        } else {
            map.put(key, value + x);
        }
    }

    static int get(TreeMap<IntegerIntegermapint key) {
        Integer value = map.get(key);
        if (value == null) {
            return 0;
        }
        return value;
    }

}


No comments:

Post a Comment