250628 평행우주

Jongleee·2025년 6월 28일

TIL

목록 보기
943/970
private static class Edge {
	int to;
	Edge next;

	Edge(int to, Edge next) {
		this.to = to;
		this.next = next;
	}
}

private static class TreeHash implements Comparable<TreeHash> {
	int size;
	long hash;

	TreeHash(long hash, int size) {
		this.hash = hash;
		this.size = size;
	}

	@Override
	public int compareTo(TreeHash o) {
		if (this.size == o.size) {
			return Long.compare(this.hash, o.hash);
		}
		return this.size- o.size;
	}
}

public static void main(String[] args) throws IOException {
	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	int testCount = Integer.parseInt(br.readLine());
	Set<Long> uniqueTreeHashes = new HashSet<>();

	while (testCount-- > 0) {
		int nodeCount = Integer.parseInt(br.readLine());
		Edge[] adj = new Edge[nodeCount];
		for (int i = 1; i < nodeCount; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int u = Integer.parseInt(st.nextToken());
			int v = Integer.parseInt(st.nextToken());
			adj[u] = new Edge(v, adj[u]);
			adj[v] = new Edge(u, adj[v]);
		}

		int[] subSize = new int[nodeCount];
		int threshold = computeSubtreeSize(0, -1, adj, subSize) >> 1;

		Set<Integer> centroids = new HashSet<>();
		int centroid = findCentroid(0, -1, threshold, adj, subSize);
		centroids.add(centroid);
		addSecondaryCentroids(centroid, -1, threshold, adj, subSize, centroids, nodeCount);

		TreeHash bestTree = new TreeHash(-1L, -1);
		for (int cent : centroids) {
			bestTree = getMaxTree(bestTree, computeHash(cent, -1, adj));
		}

		uniqueTreeHashes.add(bestTree.hash);
	}

	System.out.println(uniqueTreeHashes.size());
}

private static int computeSubtreeSize(int current, int parent, Edge[] adj, int[] subSize) {
	subSize[current] = 1;
	for (Edge edge = adj[current]; edge != null; edge = edge.next) {
		if (edge.to == parent)
			continue;
		subSize[current] += computeSubtreeSize(edge.to, current, adj, subSize);
	}
	return subSize[current];
}

private static int findCentroid(int current, int parent, int threshold, Edge[] adj, int[] subSize) {
	for (Edge edge = adj[current]; edge != null; edge = edge.next) {
		if (edge.to == parent)
			continue;
		if (subSize[edge.to] > threshold) {
			return findCentroid(edge.to, current, threshold, adj, subSize);
		}
	}
	return current;
}

private static void addSecondaryCentroids(int current, int parent, int threshold,
		Edge[] adj, int[] subSize, Set<Integer> centroids, int totalSize) {
	if ((totalSize & 1) == 1)
		return;

	for (Edge edge = adj[current]; edge != null; edge = edge.next) {
		if (edge.to == parent)
			continue;

		int partialSize = 1;
		boolean isValid = true;

		if (subSize[edge.to] - 1 > threshold)
			continue;

		for (Edge subEdge = adj[edge.to]; subEdge != null; subEdge = subEdge.next) {
			if (subEdge.to == current)
				continue;
			partialSize += subSize[subEdge.to];
			if (subSize[subEdge.to] > threshold)
				isValid = false;
		}

		int remaining = totalSize - partialSize;
		if (isValid && remaining <= threshold) {
			centroids.add(edge.to);
		}
	}
}

private static TreeHash computeHash(int current, int parent, Edge[] adj) {
	List<TreeHash> children = new ArrayList<>();

	for (Edge edge = adj[current]; edge != null; edge = edge.next) {
		if (edge.to == parent)
			continue;
		children.add(computeHash(edge.to, current, adj));
	}

	Collections.sort(children);
	TreeHash result = new TreeHash(1L, 1);

	for (TreeHash child : children) {
		result.hash <<= child.size;
		result.hash |= child.hash;
		result.size += child.size;
	}

	result.hash <<= 1;
	result.size++;

	return result;
}

private static TreeHash getMaxTree(TreeHash a, TreeHash b) {
	return (a.compareTo(b) > 0) ? a : b;
}

출처:https://www.acmicpc.net/problem/18123

0개의 댓글