Implement with Union-find. O(mlogn)