結果
| 問題 |
No.416 旅行会社
|
| コンテスト | |
| ユーザー |
norioc
|
| 提出日時 | 2018-01-14 11:44:16 |
| 言語 | D (dmd 2.109.1) |
| 結果 |
AC
|
| 実行時間 | 441 ms / 4,000 ms |
| コード長 | 2,890 bytes |
| コンパイル時間 | 748 ms |
| コンパイル使用メモリ | 108,288 KB |
| 実行使用メモリ | 28,672 KB |
| 最終ジャッジ日時 | 2024-06-12 23:34:18 |
| 合計ジャッジ時間 | 6,546 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 21 |
ソースコード
import std.algorithm;
import std.array;
import std.conv;
import std.math;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
int readint() { return readln.chomp.to!int; }
int[] readints() { return readln.split.to!(int[]); }
alias Pair = Tuple!(int, "a", int, "b");
Pair readPair() {
auto xs = readints;
return Pair(xs[0], xs[1]);
}
void main() {
auto nmq = readints;
int n = nmq[0], m = nmq[1], q = nmq[2];
Pair[] pairs;
for (int i = 0; i < m; i++) {
pairs ~= readPair();
}
bool[Pair] breakMap;
Pair[] breaks;
for (int i = 0; i < q; i++) {
auto p = readPair();
breaks ~= p;
breakMap[p] = true;
}
auto uf = new UnionFind(n);
foreach (p; pairs) {
// 破壊に関係ない橋を予め接続しておく
if (p !in breakMap) {
uf.unite(p.a, p.b);
}
}
auto ans = new int[](n + 1);
ans[] = -1; // 全て到達できる
foreach_reverse (i, brk; breaks) {
const ra = uf.root(brk.a);
const rb = uf.root(brk.b);
const r1 = uf.root(1);
if (ra != rb && (ra == r1 || rb == r1)) {
int nth = cast(int) i + 1;
int node = ra == r1 ? rb : ra; // 1 と接続された集合のルート
uf.doEach(node, delegate(e) { ans[e] = nth; });
}
uf.unite(brk.a, brk.b);
}
for (int i = 2; i <= n; i++) {
if (uf.isSame(1, i))
writeln(ans[i]);
else
writeln(0); // 最初から到達できない
}
}
class UnionFind {
private int[] _data;
private int[] _nexts; // 次の要素。なければ -1
private int[] _tails; // 末尾の要素
this(int n) {
_data = new int[](n + 1);
_nexts = new int[](n + 1);
_tails = new int[](n + 1);
_data[] = -1;
_nexts[] = -1;
for (int i = 0; i < _tails.length; i++)
_tails[i] = i;
}
int root(int a) {
if (_data[a] < 0) return a;
return _data[a] = root(_data[a]);
}
bool unite(int a, int b) {
int ra = root(a);
int rb = root(b);
if (ra == rb) return false;
// ra に rb を繋げる
_data[ra] += _data[rb];
_data[rb] = ra;
// ra の末尾の後ろに rb を繋げる
_nexts[_tails[ra]] = rb;
// ra の末尾が rb の末尾になる
_tails[ra] = _tails[rb];
return true;
}
bool isSame(int a, int b) {
return root(a) == root(b);
}
/// a が属する集合のサイズ
int groupSize(int a) {
return -_data[root(a)];
}
/// a が属する集合の要素全て
void doEach(int a, void delegate(int) fn) {
auto node = root(a);
while (node != -1) {
fn(node);
node = _nexts[node];
}
}
}
norioc