結果

問題 No.1293 2種類の道路
ユーザー ks2mks2m
提出日時 2020-11-20 21:58:11
言語 Java21
(openjdk 21)
結果
WA  
実行時間 -
コード長 4,672 bytes
コンパイル時間 3,064 ms
コンパイル使用メモリ 96,836 KB
実行使用メモリ 99,192 KB
最終ジャッジ日時 2024-07-23 12:58:07
合計ジャッジ時間 14,850 ms
ジャッジサーバーID
(参考情報)
judge1 / judge5
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 63 ms
50,568 KB
testcase_01 AC 62 ms
50,464 KB
testcase_02 AC 60 ms
50,328 KB
testcase_03 AC 61 ms
50,656 KB
testcase_04 WA -
testcase_05 AC 60 ms
50,236 KB
testcase_06 AC 62 ms
50,696 KB
testcase_07 AC 62 ms
50,464 KB
testcase_08 AC 75 ms
50,704 KB
testcase_09 WA -
testcase_10 WA -
testcase_11 WA -
testcase_12 WA -
testcase_13 WA -
testcase_14 AC 745 ms
99,192 KB
testcase_15 WA -
testcase_16 AC 770 ms
80,256 KB
testcase_17 AC 768 ms
85,544 KB
testcase_18 AC 658 ms
84,684 KB
testcase_19 WA -
testcase_20 WA -
testcase_21 AC 435 ms
58,520 KB
testcase_22 AC 452 ms
58,776 KB
testcase_23 AC 445 ms
58,888 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Main {
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] sa = br.readLine().split(" ");
		int n = Integer.parseInt(sa[0]);
		int p = Integer.parseInt(sa[1]);
		int q = Integer.parseInt(sa[2]);
		DSU uf1 = new DSU(n);
		Set<Integer> set1 = new HashSet<>();
		for (int i = 0; i < p; i++) {
			sa = br.readLine().split(" ");
			int a = Integer.parseInt(sa[0]) - 1;
			int b = Integer.parseInt(sa[1]) - 1;
			uf1.merge(a, b);
			set1.add(a);
			set1.add(b);
		}
		DSU uf2 = new DSU(n);
		Set<Integer> set2 = new HashSet<>();
		for (int i = 0; i < q; i++) {
			sa = br.readLine().split(" ");
			int a = Integer.parseInt(sa[0]) - 1;
			int b = Integer.parseInt(sa[1]) - 1;
			uf2.merge(a, b);
			set2.add(a);
			set2.add(b);
		}
		br.close();

		List<List<Integer>> g1 = uf1.groups();
		List<List<Integer>> g2 = uf2.groups();
		Map<Integer, Set<Integer>> g22 = new HashMap<>();
		for (int i = 0; i < g2.size(); i++) {
			List<Integer> list = g2.get(i);
			Set<Integer> set = new HashSet<>();
			int l = uf2.leader(list.get(0));
			for (Integer o : list) {
				if (!set1.contains(o)) {
					set.add(o);
				}
			}
			g22.put(l, set);
		}
		long ans = 0;
		for (int i = 0; i < g1.size(); i++) {
			List<Integer> list = g1.get(i);
			if (!set1.contains(list.get(0))) {
				continue;
			}
			Set<Integer> set = new HashSet<>();
			for (int o : list) {
				set.add(uf2.leader(o));
			}
			long cnt = 0;
			for (Integer o : set) {
				cnt += g22.get(o).size();
			}
			ans += (long) list.size() * (list.size() - 1 + cnt);
		}

		for (int i = 0; i < g2.size(); i++) {
			List<Integer> list = g2.get(i);
			if (!set2.contains(list.get(0))) {
				continue;
			}
			long size = list.size();
			ans += (long) g22.get(uf2.leader(list.get(0))).size() * (size - 1);
		}
		System.out.println(ans);
	}
}

/**
 * Disjoint Set Union(Union Find)
 */
class DSU {
	private int n;
	private int[] parentOrSize;
	private int num;

	/**
	 * n頂点0辺の無向グラフを作る。<br>
	 * O(n)
	 * 
	 * @param n 頂点数
	 */
	public DSU(int n) {
		this.n = n;
		this.parentOrSize = new int[n];
		Arrays.fill(parentOrSize, -1);
		num = n;
	}

	/**
	 * 辺(a, b)を足す。<br>
	 * ならしO(α(n))
	 * 
	 * @param a 頂点番号(0≦a<n)
	 * @param b 頂点番号(0≦b<n)
	 * @return 代表元
	 */
	int merge(int a, int b) {
		assert 0 <= a && a < n : "a=" + a;
		assert 0 <= b && b < n : "b=" + b;

		int x = leader(a);
		int y = leader(b);
		if (x == y) {
			return x;
		}
		if (-parentOrSize[x] < -parentOrSize[y]) {
			int tmp = x;
			x = y;
			y = tmp;
		}
		parentOrSize[x] += parentOrSize[y];
		parentOrSize[y] = x;
		num--;
		return x;
	}

	/**
	 * 頂点a, bが連結かどうか。<br>
	 * ならしO(α(n))
	 * 
	 * @param a 頂点番号(0≦a<n)
	 * @param b 頂点番号(0≦b<n)
	 * @return true:連結 false:非連結
	 */
	boolean same(int a, int b) {
		assert 0 <= a && a < n : "a=" + a;
		assert 0 <= b && b < n : "b=" + b;

		return leader(a) == leader(b);
	}

	/**
	 * 頂点aの属する連結成分の代表元を返す。<br>
	 * ならしO(α(n))
	 * 
	 * @param a 頂点番号(0≦a<n)
	 * @return 代表元
	 */
	int leader(int a) {
		assert 0 <= a && a < n : "a=" + a;

		if (parentOrSize[a] < 0) {
			return a;
		} else {
			return parentOrSize[a] = leader(parentOrSize[a]);
		}
	}

	/**
	 * 頂点aの属する連結成分の要素数を返す。<br>
	 * ならしO(α(n))
	 * 
	 * @param a 頂点番号(0≦a<n)
	 * @return 要素数
	 */
	int size(int a) {
		assert 0 <= a && a < n : "a=" + a;

		return -parentOrSize[leader(a)];
	}

	/**
	 * 連結成分の数を返す。<br>
	 * O(1)
	 * 
	 * @return 連結成分数
	 */
	int num() {
		return num;
	}

	/**
	 * グラフを連結成分に分けた情報を返す。<br>
	 * O(n)
	 * 
	 * @return 「1つの連結成分の頂点番号のリスト」のリスト
	 */
	List<List<Integer>> groups() {
		int[] leaderBuf = new int[n];
		int[] groupSize = new int[n];
		for (int i = 0; i < n; i++) {
			leaderBuf[i] = leader(i);
			groupSize[leaderBuf[i]]++;
		}
		List<List<Integer>> result = new ArrayList<>(n);
		for (int i = 0; i < n; i++) {
			result.add(new ArrayList<>(groupSize[i]));
		}
		for (int i = 0; i < n; i++) {
			result.get(leaderBuf[i]).add(i);
		}
		result.removeIf(List::isEmpty);
		return result;
	}
}
0